Skip to content

Commit 3c0d261

Browse files
scezenassouktim
andauthored
[DERCBOT-1329] Support filtering for Annotations + refined Dialogs filters (#1845)
* withAnnotations bool * [DERCBOT-1329] Fix annotation filter * Filter by annotation presence, by cumulative state, by cumulative reason * Sort by annotation lastUpdateDate * Filters addition * Filtering by dialog creationDate & sort by ASC/DESC order * FaqSettings files * Single POST endpoint for creation/update of an annotation * pr fix * Revert "FaqSettings files" This reverts commit 21fb259. * rollback on FaqSettings * rollback on FaqSettings V2 --------- Co-authored-by: Mohamed ASSOUKTI <mohamed.assoukti@partnre.com>
1 parent 9dfcebf commit 3c0d261

File tree

11 files changed

+279
-53
lines changed

11 files changed

+279
-53
lines changed

bot/admin/server/src/main/kotlin/BotAdminService.kt

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,47 @@ object BotAdminService {
153153
}
154154
}
155155

156+
fun saveAnnotation(
157+
dialogId: String,
158+
actionId: String,
159+
annotationDTO: BotAnnotationDTO,
160+
user: String
161+
): BotAnnotation {
162+
return if (dialogReportDAO.annotationExists(dialogId, actionId)) {
163+
updateAnnotation(dialogId, actionId, annotationDTO, user)
164+
} else {
165+
createAnnotation(dialogId, actionId, annotationDTO, user)
166+
}
167+
}
168+
169+
private fun createAnnotation(
170+
dialogId: String,
171+
actionId: String,
172+
annotationDTO: BotAnnotationDTO,
173+
user: String
174+
): BotAnnotation {
175+
val annotation = BotAnnotation(
176+
state = annotationDTO.state,
177+
reason = annotationDTO.reason,
178+
description = annotationDTO.description,
179+
groundTruth = annotationDTO.groundTruth,
180+
events = mutableListOf(
181+
BotAnnotationEventState(
182+
eventId = newId(),
183+
creationDate = Instant.now(),
184+
lastUpdateDate = Instant.now(),
185+
user = user,
186+
before = null,
187+
after = annotationDTO.state.name
188+
)
189+
),
190+
lastUpdateDate = Instant.now()
191+
)
192+
193+
dialogReportDAO.insertAnnotation(dialogId, actionId, annotation)
194+
return annotation
195+
}
196+
156197
fun addCommentToAnnotation(
157198
dialogId: String,
158199
actionId: String,
@@ -314,39 +355,6 @@ object BotAdminService {
314355
)
315356
}
316357

317-
fun createAnnotation(
318-
dialogId: String,
319-
actionId: String,
320-
annotationDTO: BotAnnotationDTO,
321-
user: String
322-
): BotAnnotation {
323-
if (dialogReportDAO.annotationExists(dialogId, actionId)) {
324-
throw IllegalStateException("An annotation already exists for this action")
325-
}
326-
327-
val annotation = BotAnnotation(
328-
state = annotationDTO.state,
329-
reason = annotationDTO.reason,
330-
description = annotationDTO.description,
331-
groundTruth = annotationDTO.groundTruth,
332-
events = mutableListOf(),
333-
lastUpdateDate = Instant.now()
334-
)
335-
336-
val event = BotAnnotationEventState(
337-
eventId = newId(),
338-
creationDate = Instant.now(),
339-
lastUpdateDate = Instant.now(),
340-
user = user,
341-
before = null,
342-
after = annotationDTO.state.name
343-
)
344-
345-
annotation.events.add(event)
346-
dialogReportDAO.insertAnnotation(dialogId, actionId, annotation)
347-
return annotation
348-
}
349-
350358
fun createOrGetIntent(
351359
namespace: String,
352360
intentName: String,

bot/admin/server/src/main/kotlin/model/DialogsSearchQuery.kt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616

1717
package ai.tock.bot.admin.model
1818

19+
import ai.tock.bot.admin.annotation.BotAnnotationReasonType
20+
import ai.tock.bot.admin.annotation.BotAnnotationState
1921
import ai.tock.bot.admin.dialog.DialogReportQuery
2022
import ai.tock.bot.connector.ConnectorType
23+
import ai.tock.bot.engine.dialog.SortDirection
2124
import ai.tock.bot.engine.user.PlayerId
2225
import ai.tock.nlp.admin.model.PaginatedQuery
26+
import java.time.ZonedDateTime
2327

2428
/**
2529
*
@@ -36,7 +40,16 @@ data class DialogsSearchQuery(
3640
val ratings: Set<Int> = emptySet(),
3741
val applicationId: String?,
3842
val intentsToHide: Set<String> = emptySet(),
39-
val isGenAiRagDialog: Boolean?
43+
val isGenAiRagDialog: Boolean?,
44+
val withAnnotations: Boolean?,
45+
val annotationStates: Set<BotAnnotationState> = emptySet(),
46+
val annotationReasons: Set<BotAnnotationReasonType> = emptySet(),
47+
val annotationSort: SortDirection? = null,
48+
val dialogSort: SortDirection? = null,
49+
val annotationCreationDateFrom: ZonedDateTime? = null,
50+
val annotationCreationDateTo: ZonedDateTime? = null,
51+
val dialogCreationDateFrom: ZonedDateTime? = null,
52+
val dialogCreationDateTo: ZonedDateTime? = null,
4053
) : PaginatedQuery() {
4154

4255
fun toDialogReportQuery(): DialogReportQuery {
@@ -57,7 +70,16 @@ data class DialogsSearchQuery(
5770
ratings = ratings,
5871
applicationId = applicationId,
5972
intentsToHide = intentsToHide,
60-
isGenAiRagDialog = isGenAiRagDialog
73+
isGenAiRagDialog = isGenAiRagDialog,
74+
withAnnotations = withAnnotations,
75+
annotationStates = annotationStates,
76+
annotationReasons = annotationReasons,
77+
annotationSort = annotationSort,
78+
dialogSort = dialogSort,
79+
annotationCreationDateFrom = annotationCreationDateFrom,
80+
annotationCreationDateTo = annotationCreationDateTo,
81+
dialogCreationDateFrom = dialogCreationDateFrom,
82+
dialogCreationDateTo = dialogCreationDateTo,
6183
)
6284
}
6385
}

bot/admin/server/src/main/kotlin/verticle/DialogVerticle.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,11 @@ class DialogVerticle {
176176

177177
// --------------------------------- Annotation Routes ----------------------------------
178178

179-
// CREATE ANNOTATION
179+
// CREATE/UPDATE ANNOTATION
180180
blockingJsonPost(PATH_ANNOTATION, setOf(TockUserRole.botUser)) { context, annotationDTO: BotAnnotationDTO ->
181181
val botId = context.path("botId")
182182
context.checkBotId(botId)
183-
BotAdminService.createAnnotation(
183+
BotAdminService.saveAnnotation(
184184
context.path("dialogId"),
185185
context.path("actionId"),
186186
annotationDTO,

bot/engine/src/main/kotlin/admin/annotation/BotAnnotation.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@
1717
package ai.tock.bot.admin.annotation
1818

1919

20-
import org.litote.kmongo.Id
21-
import org.litote.kmongo.newId
2220
import java.time.Instant
2321

2422
data class BotAnnotation(
25-
val _id: Id<Annotation> = newId(),
2623
var state: BotAnnotationState,
2724
var reason: BotAnnotationReasonType?,
2825
var description: String,

bot/engine/src/main/kotlin/admin/dialog/DialogReportQuery.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package ai.tock.bot.admin.dialog
1818

19+
import ai.tock.bot.admin.annotation.BotAnnotationReasonType
20+
import ai.tock.bot.admin.annotation.BotAnnotationState
1921
import ai.tock.bot.connector.ConnectorType
22+
import ai.tock.bot.engine.dialog.SortDirection
2023
import ai.tock.bot.engine.user.PlayerId
2124
import java.time.ZonedDateTime
2225
import java.util.Locale
@@ -60,5 +63,15 @@ data class DialogReportQuery(
6063

6164
val intentsToHide : Set<String> = emptySet(),
6265

63-
val isGenAiRagDialog: Boolean? = null
66+
val isGenAiRagDialog: Boolean? = null,
67+
68+
val withAnnotations: Boolean? = null,
69+
val annotationStates: Set<BotAnnotationState> = emptySet(),
70+
val annotationReasons: Set<BotAnnotationReasonType> = emptySet(),
71+
val annotationSort: SortDirection? = null,
72+
val dialogSort: SortDirection? = null,
73+
val annotationCreationDateFrom: ZonedDateTime? = null,
74+
val annotationCreationDateTo: ZonedDateTime? = null,
75+
val dialogCreationDateFrom: ZonedDateTime? = null,
76+
val dialogCreationDateTo: ZonedDateTime? = null,
6477
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (C) 2017/2021 e-voyageurs technologies
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package ai.tock.bot.engine.dialog
18+
19+
enum class SortDirection {
20+
ASC,
21+
DESC
22+
}

bot/storage-mongo/src/main/kotlin/BotDataRegistry.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package ai.tock.bot.mongo
1818

19+
import ai.tock.bot.admin.annotation.BotAnnotation
1920
import ai.tock.bot.admin.bot.BotApplicationConfiguration
2021
import ai.tock.bot.admin.bot.BotConfiguration
2122
import ai.tock.bot.admin.story.StoryDefinitionConfiguration
@@ -49,7 +50,8 @@ import org.litote.kmongo.DataRegistry
4950
PlayerId::class,
5051
EventState::class,
5152
ConnectorType::class,
52-
ActionMetadata::class
53+
ActionMetadata::class,
54+
BotAnnotation::class
5355
]
5456
)
5557
@JacksonDataRegistry(

bot/storage-mongo/src/main/kotlin/UserTimelineMongoDAO.kt

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@ import ai.tock.bot.definition.BotDefinition
2424
import ai.tock.bot.definition.StoryDefinition
2525
import ai.tock.bot.engine.action.Action
2626
import ai.tock.bot.engine.action.SendSentence
27-
import ai.tock.bot.engine.dialog.ArchivedEntityValue
28-
import ai.tock.bot.engine.dialog.Dialog
29-
import ai.tock.bot.engine.dialog.EntityStateValue
30-
import ai.tock.bot.engine.dialog.Snapshot
27+
import ai.tock.bot.engine.dialog.*
3128
import ai.tock.bot.engine.nlp.NlpCallStats
3229
import ai.tock.bot.engine.nlp.NlpStats
3330
import ai.tock.bot.engine.user.PlayerId
@@ -47,6 +44,7 @@ import ai.tock.bot.mongo.DialogTextCol_.Companion.Text
4744
import ai.tock.bot.mongo.MongoBotConfiguration.database
4845
import ai.tock.bot.mongo.NlpStatsCol_.Companion.AppNamespace
4946
import ai.tock.bot.mongo.UserTimelineCol_.Companion.ApplicationIds
47+
import ai.tock.bot.mongo.UserTimelineCol_.Companion.CreationDate
5048
import ai.tock.bot.mongo.UserTimelineCol_.Companion.LastUpdateDate
5149
import ai.tock.bot.mongo.UserTimelineCol_.Companion.LastUserActionDate
5250
import ai.tock.bot.mongo.UserTimelineCol_.Companion.Namespace
@@ -63,9 +61,6 @@ import com.mongodb.client.model.ReplaceOptions
6361
import mu.KotlinLogging
6462
import org.litote.kmongo.*
6563
import org.litote.kmongo.MongoOperator.*
66-
import kotlinx.coroutines.newSingleThreadContext
67-
import kotlinx.coroutines.runBlocking
68-
import kotlinx.coroutines.withContext
6964
import java.time.Instant
7065
import java.time.Instant.now
7166
import java.time.ZoneOffset
@@ -597,16 +592,45 @@ internal object UserTimelineMongoDAO : UserTimelineDAO, UserReportDAO, DialogRep
597592
if (query.intentName.isNullOrBlank()) null else Stories.currentIntent.name_ eq query.intentName,
598593
if (query.ratings.isNotEmpty()) DialogCol_.Rating `in` query.ratings.toSet() else null,
599594
if (query.applicationId.isNullOrBlank()) null else DialogCol_.ApplicationIds `in` setOf( query.applicationId),
600-
if (query.isGenAiRagDialog == true) Stories.actions.botMetadata.isGenAiRagAnswer eq true else null
595+
if (query.isGenAiRagDialog == true) Stories.actions.botMetadata.isGenAiRagAnswer eq true else null,
596+
if (query.withAnnotations == true) Stories.actions.annotation.state `in` BotAnnotationState.entries else null,
597+
if (query.annotationStates.isNotEmpty()) Stories.actions.annotation.state `in` query.annotationStates else null,
598+
if (query.annotationReasons.isNotEmpty()) Stories.actions.annotation.reason `in` query.annotationReasons else null,
599+
if (annotationCreationDateFrom == null) null
600+
else Stories.actions.annotation.creationDate gt annotationCreationDateFrom?.toInstant(),
601+
if (annotationCreationDateTo == null) null
602+
else Stories.actions.annotation.creationDate lt annotationCreationDateTo?.toInstant(),
603+
if (dialogCreationDateFrom == null) null
604+
else Stories.actions.date gt dialogCreationDateFrom?.toInstant(),
605+
if (dialogCreationDateTo == null) null
606+
else Stories.actions.date lt dialogCreationDateTo?.toInstant(),
601607
)
602608
logger.debug { "dialog search query: $filter" }
603609
val c = dialogCol.withReadPreference(secondaryPreferred())
604610
val count = c.countDocuments(filter, defaultCountOptions)
605611
return if (count > start) {
612+
val sortBson = when {
613+
annotationSort != null -> {
614+
if (annotationSort == SortDirection.ASC)
615+
ascending(Stories.actions.annotation.lastUpdateDate)
616+
else
617+
descending(Stories.actions.annotation.lastUpdateDate)
618+
}
619+
620+
dialogSort != null -> {
621+
if (dialogSort == SortDirection.ASC)
622+
orderBy(mapOf(Stories.actions.date to true))
623+
else
624+
orderBy(mapOf(Stories.actions.date to false))
625+
}
626+
627+
// If no filter is specified, we keep default filtering
628+
else -> descending(LastUpdateDate)
629+
}
606630
val list = c.find(filter)
607631
.skip(start.toInt())
608632
.limit(size)
609-
.descendingSort(LastUpdateDate)
633+
.sort(sortBson)
610634
.run {
611635
map { it.toDialogReport() }
612636
.toList()

0 commit comments

Comments
 (0)