Repository: iai-group/DialogueKit (language: python)

Issue:
Add utterance level feedback 
Maybe an utterance id (e.g., {user_id}_{conversation_id}_{turn_id}) and feedback (like, dislike) properties on Utterance class.


Discussion / hints:
I am not against the idea of the id but I am not sure where it would be necessary. 
For the feedback, I wonder if it can be considered as an annotation, hence belongs more to the class `AnnotatedUtterance`.
I would personally add an enum for feedback (positive, negative, ambivalent, etc.) and then have it on the utterance level. I wouldn't put it under `AnnotatedUtterance` because we don't actually need annotations for an utterance to have feedback. At least from my shallow understanding of the code. 
ID on the utterances is useful, e.g., if we want to save/load data on the utterance level. Consider adding a dash between the components.

+1 to Weronika's response regarding feedback. This would deserve a class on its own as it's not the type of annotation that AnnotatedUtterance is meant to capture (which are system annotations). There could be a case when feedback is also included there, but then a Feedback object can be linked.

Fix patch:
diff --git a/dialoguekit/core/feedback.py b/dialoguekit/core/feedback.py
new file mode 100644
index 00000000..6525b484
--- /dev/null
+++ b/dialoguekit/core/feedback.py
@@ -0,0 +1,23 @@
+"""Interface representing user's feedback.
+
+Currently only binary feedback is supported on the utterance level.
+Later, it might be extended to graded feedback as well as with
+conversation-level feedback.
+"""
+from dataclasses import dataclass, field
+from enum import Enum
+
+
+class BinaryFeedback(Enum):
+    """Represents binary feedback provided by a user."""
+
+    NEGATIVE = 0
+    POSITIVE = 1
+
+
+@dataclass(eq=True, unsafe_hash=True)
+class UtteranceFeedback:
+    """Represents feedback provided for the utterance."""
+
+    utterance_id: str = field(hash=True)
+    feedback: BinaryFeedback = field(hash=True)


Test patch:
diff --git a/tests/core/test_feedback.py b/tests/core/test_feedback.py
new file mode 100644
index 00000000..b38dedfc
--- /dev/null
+++ b/tests/core/test_feedback.py
@@ -0,0 +1,22 @@
+"""Test UtteranceFeedback class."""
+from dialoguekit.core.feedback import BinaryFeedback, UtteranceFeedback
+
+
+def test_initialization():
+    """Tests utterance feedback initialization."""
+    f1 = UtteranceFeedback("utterance_1", BinaryFeedback.POSITIVE)
+    assert isinstance(f1, UtteranceFeedback)
+    assert f1.feedback == BinaryFeedback.POSITIVE
+
+
+def test_comparison():
+    """Tests utterance feedback comparison."""
+    f1 = UtteranceFeedback("utterance_1", BinaryFeedback.POSITIVE)
+    f2 = f1
+    assert f1 == f2
+
+    f3 = UtteranceFeedback("utterance_1", BinaryFeedback.POSITIVE)
+    assert f1 == f3
+
+    f4 = UtteranceFeedback("utterance_1", BinaryFeedback.NEGATIVE)
+    assert f1 != f4
diff --git a/tests/core/test_utterance.py b/tests/core/test_utterance.py
index d1d001e1..8493bcf0 100644
--- a/tests/core/test_utterance.py
+++ b/tests/core/test_utterance.py
@@ -1,5 +1,6 @@
 """Tests for the Utterance class."""
 import pytest
+
 from dialoguekit.core import Utterance
 from dialoguekit.participant import DialogueParticipant