Skip to content

Commit 67a76ca

Browse files
committed
[DERCBOT-1314] Documentation
Adding modifications Typo [DERCBOT-1309] Documentation update + Annotation Model Move Model files + Add Annotation as a subdocument of an Action Update Action and Dialog to support single annotation per action DAO update to allow Annotation insertion in Action subdocument Initiate BotAnnotationEvent as emptyList Business logic + Annotation creation endpoint Model update, refacto and addEvent endpoint logic Update and Delete event endpoint Restore removed byStory endpoint DialogsVerticle + Annotation presence check Improvements Dialog Endpoints to DialogVerticle Update logic to retrieve annotations from /dialogs/search endpoint Modify annotation with PUT endpoint lastUpdateDate logic added Unused import Fix malfunctioning logic + Doc update Add initial event at annotation creation PR Review Rebase + fix canEdit bool Refacto and BotAnnotationUpdateDTO delete Doc update with latest endpoints Annotation on dialogs endpoint + canEdit logic fix namespace & botId check for annotation endpoints annotationId logic removal + doc & endpoint update Fix canEdit logic on updateAnnotation & updateAnnotationEvent
1 parent a574822 commit 67a76ca

27 files changed

+1484
-28
lines changed

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

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package ai.tock.bot.admin
1818

1919
import ai.tock.bot.admin.FaqAdminService.FAQ_CATEGORY
20+
import ai.tock.bot.admin.annotation.*
2021
import ai.tock.bot.admin.answer.AnswerConfiguration
2122
import ai.tock.bot.admin.answer.AnswerConfigurationType.builtin
2223
import ai.tock.bot.admin.answer.AnswerConfigurationType.script
@@ -46,6 +47,7 @@ import ai.tock.bot.admin.story.dump.*
4647
import ai.tock.bot.admin.user.UserReportDAO
4748
import ai.tock.bot.connector.ConnectorType
4849
import ai.tock.bot.definition.IntentWithoutNamespace
50+
import ai.tock.bot.engine.action.Action
4951
import ai.tock.bot.engine.config.SatisfactionIntent
5052
import ai.tock.bot.engine.dialog.Dialog
5153
import ai.tock.bot.engine.dialog.DialogFlowDAO
@@ -62,6 +64,7 @@ import ai.tock.nlp.front.shared.config.*
6264
import ai.tock.nlp.front.shared.config.ClassifiedSentenceStatus.model
6365
import ai.tock.nlp.front.shared.config.ClassifiedSentenceStatus.validated
6466
import ai.tock.shared.*
67+
import ai.tock.shared.exception.rest.NotFoundException
6568
import ai.tock.shared.security.UserLogin
6669
import ai.tock.shared.security.key.HasSecretKey
6770
import ai.tock.shared.security.key.SecretKey
@@ -70,6 +73,7 @@ import ai.tock.translator.*
7073
import com.github.salomonbrys.kodein.instance
7174
import mu.KotlinLogging
7275
import org.litote.kmongo.Id
76+
import org.litote.kmongo.newId
7377
import org.litote.kmongo.toId
7478
import java.time.Instant
7579
import java.util.*
@@ -149,6 +153,200 @@ object BotAdminService {
149153
}
150154
}
151155

156+
fun addCommentToAnnotation(
157+
dialogId: String,
158+
actionId: String,
159+
eventDTO: BotAnnotationEventDTO,
160+
user: String
161+
): BotAnnotationEvent {
162+
if (eventDTO.type != BotAnnotationEventType.COMMENT) {
163+
throw IllegalArgumentException("Only COMMENT events are allowed")
164+
}
165+
166+
require(!eventDTO.comment.isNullOrBlank()) { "Comment is required and cannot be blank for COMMENT event type" }
167+
168+
val annotation = dialogReportDAO.findAnnotation(dialogId, actionId)
169+
?: throw IllegalStateException("Annotation not found")
170+
171+
val event = BotAnnotationEventComment(
172+
eventId = newId(),
173+
creationDate = Instant.now(),
174+
lastUpdateDate = Instant.now(),
175+
user = user,
176+
comment = eventDTO.comment ?: throw IllegalArgumentException("Comment required")
177+
)
178+
179+
dialogReportDAO.addAnnotationEvent(dialogId, actionId, event)
180+
181+
return event.copy(canEdit = true)
182+
}
183+
184+
fun updateAnnotationEvent(
185+
dialogId: String,
186+
actionId: String,
187+
eventId: String,
188+
eventDTO: BotAnnotationEventDTO,
189+
user: String
190+
): BotAnnotationEvent {
191+
val existingEvent = dialogReportDAO.getAnnotationEvent(dialogId, actionId, eventId)
192+
?: throw IllegalArgumentException("Event not found")
193+
194+
if (existingEvent.type != BotAnnotationEventType.COMMENT) {
195+
throw IllegalArgumentException("Only comment events can be updated")
196+
}
197+
198+
if (eventDTO.type != BotAnnotationEventType.COMMENT) {
199+
throw IllegalArgumentException("Event type must be COMMENT")
200+
}
201+
202+
require(eventDTO.comment != null) { "Comment must be provided" }
203+
204+
val annotation = dialogReportDAO.findAnnotation(dialogId, actionId)
205+
?: throw IllegalStateException("Annotation not found")
206+
207+
val existingCommentEvent = existingEvent as BotAnnotationEventComment
208+
val updatedEvent = existingCommentEvent.copy(
209+
comment = eventDTO.comment!!,
210+
lastUpdateDate = Instant.now()
211+
)
212+
213+
dialogReportDAO.updateAnnotationEvent(dialogId, actionId, eventId, updatedEvent)
214+
215+
return updatedEvent.copy(canEdit = updatedEvent.user == user)
216+
}
217+
218+
fun deleteAnnotationEvent(
219+
dialogId: String,
220+
actionId: String,
221+
eventId: String,
222+
user: String
223+
) {
224+
val existingEvent = dialogReportDAO.getAnnotationEvent(dialogId, actionId, eventId)
225+
?: throw IllegalArgumentException("Event not found")
226+
227+
if (existingEvent.type != BotAnnotationEventType.COMMENT) {
228+
throw IllegalArgumentException("Only comment events can be deleted")
229+
}
230+
231+
dialogReportDAO.deleteAnnotationEvent(dialogId, actionId, eventId)
232+
}
233+
234+
fun updateAnnotation(
235+
dialogId: String,
236+
actionId: String,
237+
annotationDTO: BotAnnotationDTO,
238+
user: String
239+
): BotAnnotation {
240+
val existingAnnotation = dialogReportDAO.findAnnotation(dialogId, actionId)
241+
?: throw IllegalStateException("Annotation not found")
242+
243+
val events = mutableListOf<BotAnnotationEvent>()
244+
245+
if (existingAnnotation.state != annotationDTO.state) {
246+
events.add(
247+
BotAnnotationEventState(
248+
eventId = newId(),
249+
creationDate = Instant.now(),
250+
lastUpdateDate = Instant.now(),
251+
user = user,
252+
before = existingAnnotation.state.name,
253+
after = annotationDTO.state.name
254+
)
255+
)
256+
existingAnnotation.state = annotationDTO.state
257+
}
258+
259+
if (existingAnnotation.reason != annotationDTO.reason) {
260+
events.add(
261+
BotAnnotationEventReason(
262+
eventId = newId(),
263+
creationDate = Instant.now(),
264+
lastUpdateDate = Instant.now(),
265+
user = user,
266+
before = existingAnnotation.reason?.name,
267+
after = annotationDTO.reason?.name
268+
)
269+
)
270+
existingAnnotation.reason = annotationDTO.reason
271+
}
272+
273+
if (existingAnnotation.groundTruth != annotationDTO.groundTruth) {
274+
events.add(
275+
BotAnnotationEventGroundTruth(
276+
eventId = newId(),
277+
creationDate = Instant.now(),
278+
lastUpdateDate = Instant.now(),
279+
user = user,
280+
before = existingAnnotation.groundTruth,
281+
after = annotationDTO.groundTruth
282+
)
283+
)
284+
existingAnnotation.groundTruth = annotationDTO.groundTruth
285+
}
286+
287+
if (existingAnnotation.description != annotationDTO.description) {
288+
events.add(
289+
BotAnnotationEventDescription(
290+
eventId = newId(),
291+
creationDate = Instant.now(),
292+
lastUpdateDate = Instant.now(),
293+
user = user,
294+
before = existingAnnotation.description,
295+
after = annotationDTO.description
296+
)
297+
)
298+
existingAnnotation.description = annotationDTO.description
299+
}
300+
301+
existingAnnotation.lastUpdateDate = Instant.now()
302+
existingAnnotation.events.addAll(events)
303+
304+
dialogReportDAO.insertAnnotation(dialogId, actionId, existingAnnotation)
305+
306+
return existingAnnotation.copy(
307+
events = existingAnnotation.events.map { event ->
308+
if (event is BotAnnotationEventComment) {
309+
event.copy(canEdit = event.user == user)
310+
} else {
311+
event
312+
}
313+
}.toMutableList()
314+
)
315+
}
316+
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+
152350
fun createOrGetIntent(
153351
namespace: String,
154352
intentName: String,
@@ -216,6 +414,41 @@ object BotAdminService {
216414
}
217415
}
218416

417+
fun searchWithCommentRights(query: DialogsSearchQuery, userLogin: String): DialogReportQueryResult {
418+
val result = search(query)
419+
return result.copy(
420+
dialogs = result.dialogs.map { dialog ->
421+
processAnnotationsForUser(dialog, userLogin)
422+
}
423+
)
424+
}
425+
426+
fun getDialogWithCommentRights(id: Id<Dialog>, userLogin: String): DialogReport? {
427+
return dialogReportDAO.getDialog(id)?.let { dialog ->
428+
processAnnotationsForUser(dialog, userLogin)
429+
}
430+
}
431+
432+
private fun processAnnotationsForUser(dialog: DialogReport, userLogin: String): DialogReport {
433+
return dialog.copy(
434+
actions = dialog.actions.map { action ->
435+
action.copy(
436+
annotation = action.annotation?.let { annotation ->
437+
annotation.copy(
438+
events = annotation.events.map { event ->
439+
if (event is BotAnnotationEventComment) {
440+
event.copy(canEdit = event.user == userLogin)
441+
} else {
442+
event
443+
}
444+
}.toMutableList()
445+
)
446+
}
447+
)
448+
}
449+
)
450+
}
451+
219452
fun getIntentsInDialogs(namespace: String,nlpModel : String) : Set<String>{
220453
return dialogReportDAO.intents(namespace,nlpModel)
221454
}

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package ai.tock.bot.admin
1818

19+
1920
import ai.tock.bot.admin.BotAdminService.createI18nRequest
2021
import ai.tock.bot.admin.BotAdminService.dialogReportDAO
2122
import ai.tock.bot.admin.BotAdminService.getBotConfigurationByApplicationIdAndBotId
@@ -31,6 +32,7 @@ import ai.tock.bot.admin.story.dump.StoryDefinitionConfigurationDumpImport
3132
import ai.tock.bot.admin.test.TestPlanService
3233
import ai.tock.bot.admin.test.findTestService
3334
import ai.tock.bot.admin.verticle.GenAIVerticle
35+
import ai.tock.bot.admin.verticle.DialogVerticle
3436
import ai.tock.bot.admin.verticle.IndicatorVerticle
3537
import ai.tock.bot.connector.ConnectorType.Companion.rest
3638
import ai.tock.bot.connector.ConnectorTypeConfiguration
@@ -40,9 +42,7 @@ import ai.tock.bot.engine.config.SATISFACTION_MODULE_ID
4042
import ai.tock.bot.engine.config.UploadedFilesService
4143
import ai.tock.bot.engine.config.UploadedFilesService.downloadFile
4244
import ai.tock.bot.engine.dialog.DialogFlowDAO
43-
import ai.tock.bot.engine.message.Sentence
4445
import ai.tock.nlp.admin.AdminVerticle
45-
import ai.tock.nlp.admin.CsvCodec
4646
import ai.tock.nlp.admin.model.ApplicationScopedQuery
4747
import ai.tock.nlp.admin.model.TranslateReport
4848
import ai.tock.nlp.front.client.FrontClient
@@ -76,6 +76,7 @@ open class BotAdminVerticle : AdminVerticle() {
7676

7777
private val indicatorVerticle = IndicatorVerticle()
7878
private val aiVerticle = GenAIVerticle()
79+
private val dialogVerticle = DialogVerticle()
7980

8081
override val logger: KLogger = KotlinLogging.logger {}
8182

@@ -122,6 +123,7 @@ open class BotAdminVerticle : AdminVerticle() {
122123
configureServices()
123124

124125
indicatorVerticle.configure(this)
126+
dialogVerticle.configure(this)
125127
aiVerticle.configure(this)
126128

127129
blockingJsonPost("/users/search", botUser) { context, query: UserSearchQuery ->
@@ -216,15 +218,6 @@ open class BotAdminVerticle : AdminVerticle() {
216218
}
217219
}
218220

219-
blockingJsonPost(
220-
"/analytics/messages/byStory",
221-
setOf(botUser)
222-
) { context, request: DialogFlowRequest ->
223-
checkAndMeasure(context, request) {
224-
BotAdminAnalyticsService.reportMessagesByStory(request)
225-
}
226-
}
227-
228221
blockingJsonPost(
229222
"/analytics/messages/byStoryCategory",
230223
setOf(botUser)

0 commit comments

Comments
 (0)