Skip to content

Commit 0172211

Browse files
authored
feat: support feedback message (#781)
1 parent db25202 commit 0172211

16 files changed

Lines changed: 259 additions & 100 deletions

File tree

aperag/api/components/schemas/chat.yaml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,8 @@ chatMessage:
5555
type: array
5656
items:
5757
type: string
58-
upvote:
59-
type: number
60-
downvote:
61-
type: number
62-
revised_answer:
63-
type: string
64-
feed_back_status:
65-
type: string
66-
enum: [PENDING, RUNNING, COMPLETE, FAILED]
58+
feedback:
59+
$ref: './feedback.yaml#/feedback'
6760

6861
chatDetails:
6962
type: object
Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
feedback:
22
type: object
33
properties:
4-
upvote:
5-
type: integer
6-
downvote:
7-
type: integer
8-
revised_answer:
4+
type:
95
type: string
6+
enum:
7+
- good
8+
- bad
9+
tag:
10+
type: string
11+
enum:
12+
- Harmful
13+
- Unsafe
14+
- Fake
15+
- Unhelpful
16+
- Other
17+
message:
18+
type: string

aperag/chat/message.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from aperag.views.utils import fail
2222

2323

24-
async def feedback_message(user, chat_id, message_id, upvote, downvote, revised_answer=None):
24+
async def feedback_message(user, chat_id, message_id, feedback_type=None, feedback_tag=None, feedback_message=None):
2525
history = RedisChatMessageHistory(chat_id, redis_client=get_async_redis_client())
2626
msg = None
2727
for message in await history.messages:
@@ -33,17 +33,26 @@ async def feedback_message(user, chat_id, message_id, upvote, downvote, revised_
3333
msg = item
3434
if msg is None:
3535
return fail(HTTPStatus.NOT_FOUND, "Message not found")
36+
37+
# If feedback_type is None, delete the feedback record
38+
if feedback_type is None:
39+
try:
40+
feedback = await MessageFeedback.objects.aget(
41+
user=user, chat_id=chat_id, message_id=message_id)
42+
await feedback.adelete()
43+
return None
44+
except MessageFeedback.DoesNotExist:
45+
return None
46+
47+
# Otherwise create or update the feedback record
3648
data = {
3749
"question": msg["query"],
3850
"original_answer": msg.get("response", ""),
51+
"type": feedback_type,
52+
"tag": feedback_tag,
53+
"message": feedback_message,
3954
}
40-
if upvote is not None:
41-
data["upvote"] = upvote
42-
if downvote is not None:
43-
data["downvote"] = downvote
4455

45-
if revised_answer is not None:
46-
data["revised_answer"] = revised_answer
4756
data["status"] = MessageFeedback.Status.PENDING
4857
collection_id = msg.get("collection_id", None)
4958
feedback, _ = await MessageFeedback.objects.aupdate_or_create(

aperag/db/models.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,24 @@ class Status(models.TextChoices):
270270
COMPLETE = "COMPLETE"
271271
FAILED = "FAILED"
272272

273+
class Type(models.TextChoices):
274+
GOOD = "good"
275+
BAD = "bad"
276+
277+
class Tag(models.TextChoices):
278+
HARMFUL = "Harmful"
279+
UNSAFE = "Unsafe"
280+
FAKE = "Fake"
281+
UNHELPFUL = "Unhelpful"
282+
OTHER = "Other"
283+
273284
user = models.CharField(max_length=256)
274285
collection_id = models.CharField(max_length=24, null=True, blank=True)
275286
chat_id = models.CharField(max_length=24)
276287
message_id = models.CharField(max_length=256)
277-
upvote = models.IntegerField(default=0)
278-
downvote = models.IntegerField(default=0)
288+
type = models.CharField(max_length=16, choices=Type.choices, null=True)
289+
tag = models.CharField(max_length=16, choices=Tag.choices, null=True)
290+
message = models.TextField(null=True, blank=True)
279291
relate_ids = models.TextField(null=True)
280292
question = models.TextField(null=True, blank=True)
281293
status = models.CharField(max_length=16, choices=Status.choices, null=True)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Generated by Django 5.0.14 on 2025-04-29 15:23
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("aperag", "0003_modelserviceprovider_dialect"),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name="messagefeedback",
15+
name="downvote",
16+
),
17+
migrations.RemoveField(
18+
model_name="messagefeedback",
19+
name="upvote",
20+
),
21+
migrations.AddField(
22+
model_name="messagefeedback",
23+
name="message",
24+
field=models.TextField(blank=True, null=True),
25+
),
26+
migrations.AddField(
27+
model_name="messagefeedback",
28+
name="tag",
29+
field=models.CharField(
30+
choices=[
31+
("Harmful", "Harmful"),
32+
("Unsafe", "Unsafe"),
33+
("Fake", "Fake"),
34+
("Unhelpful", "Unhelpful"),
35+
("Other", "Other"),
36+
],
37+
max_length=16,
38+
null=True,
39+
),
40+
),
41+
migrations.AddField(
42+
model_name="messagefeedback",
43+
name="type",
44+
field=models.CharField(
45+
choices=[("good", "Good"), ("bad", "Bad")], max_length=16, null=True
46+
),
47+
),
48+
]

aperag/views/feishu.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def get_user_access_token(request, code, redirect_uri):
8282
return success({"token": token})
8383

8484

85-
def build_card_content(chat_id, message_id, message, upvote=False, downvote=False):
85+
def build_card_content(chat_id, message_id, message, feedback_type=None):
8686
return {
8787
"config": {
8888
"wide_screen_mode": True
@@ -101,9 +101,9 @@ def build_card_content(chat_id, message_id, message, upvote=False, downvote=Fals
101101
"tag": "plain_text",
102102
"content": "赞"
103103
},
104-
"type": "primary" if upvote else "default",
104+
"type": "primary" if feedback_type == "good" else "default",
105105
"value": {
106-
"upvote": True,
106+
"type": "good",
107107
"message_id": f"{message_id}",
108108
"chat_id": f"{chat_id}",
109109
}
@@ -114,9 +114,9 @@ def build_card_content(chat_id, message_id, message, upvote=False, downvote=Fals
114114
"tag": "plain_text",
115115
"content": "踩"
116116
},
117-
"type": "primary" if downvote else "default",
117+
"type": "primary" if feedback_type == "bad" else "default",
118118
"value": {
119-
"downvote": True,
119+
"type": "bad",
120120
"message_id": f"{message_id}",
121121
"chat_id": f"{chat_id}",
122122
}
@@ -128,10 +128,10 @@ def build_card_content(chat_id, message_id, message, upvote=False, downvote=Fals
128128
}
129129

130130

131-
def build_card_data(chat_id, message_id, message, upvote=False, downvote=False):
131+
def build_card_data(chat_id, message_id, message, feedback_type=None):
132132
return {
133133
"msg_type": "interactive",
134-
"content": json.dumps(build_card_content(chat_id, message_id, message, upvote, downvote)),
134+
"content": json.dumps(build_card_content(chat_id, message_id, message, feedback_type)),
135135
}
136136

137137

@@ -173,9 +173,8 @@ async def feishu_response_card_update(user, bot_id, data):
173173
value = action["value"]
174174
chat_id = value["chat_id"]
175175
msg_id = value["message_id"]
176-
upvote = value.get("upvote", None)
177-
downvote = value.get("downvote", None)
178-
await aperag.chat.message.feedback_message(user, chat_id, msg_id, upvote, downvote, "")
176+
feedback_type = value.get("type", None)
177+
await aperag.chat.message.feedback_message(user, chat_id, msg_id, feedback_type, None, None)
179178

180179
bot = await query_bot(user, bot_id)
181180
bot_config = json.loads(bot.config)
@@ -192,7 +191,7 @@ async def feishu_response_card_update(user, bot_id, data):
192191
}
193192
client = FeishuClient(ctx)
194193
token = data["token"]
195-
card = build_card_content(chat_id, msg_id, msg_cache[msg_id], upvote, downvote)
194+
card = build_card_content(chat_id, msg_id, msg_cache[msg_id], feedback_type)
196195
card["open_ids"] = [data["open_id"]]
197196
data = {
198197
"token": token,

aperag/views/main.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -844,13 +844,7 @@ async def feedback_message(request, bot_id: str, chat_id: str, message_id: str,
844844
chat = await query_chat(user, bot_id, chat_id)
845845
if chat is None:
846846
return fail(HTTPStatus.NOT_FOUND, "Chat not found")
847-
feedback = await aperag.chat.message.feedback_message(chat.user, chat_id, message_id, msg_in.upvote,
848-
msg_in.downvote,
849-
msg_in.revised_answer)
850-
851-
# embedding the revised answer
852-
if msg_in.revised_answer is not None:
853-
message_feedback.delay(feedback_id=feedback.id)
847+
feedback = await aperag.chat.message.feedback_message(chat.user, chat_id, message_id, msg_in.type, msg_in.tag, msg_in.message)
854848
return success({})
855849

856850

aperag/views/models.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# generated by datamodel-codegen:
22
# filename: openapi.merged.yaml
3-
# timestamp: 2025-04-28T12:29:12+00:00
3+
# timestamp: 2025-04-29T15:27:05+00:00
44

55
from __future__ import annotations
66

@@ -97,6 +97,12 @@ class Reference(BaseModel):
9797
metadata: Optional[dict[str, Any]] = None
9898

9999

100+
class Feedback(BaseModel):
101+
type: Optional[Literal['good', 'bad']] = None
102+
tag: Optional[Literal['Harmful', 'Unsafe', 'Fake', 'Unhelpful', 'Other']] = None
103+
message: Optional[str] = None
104+
105+
100106
class ChatMessage(BaseModel):
101107
id: Optional[str] = None
102108
type: Optional[Literal['welcome', 'message', 'start', 'stop', 'error']] = None
@@ -105,12 +111,7 @@ class ChatMessage(BaseModel):
105111
data: Optional[str] = None
106112
references: Optional[list[Reference]] = None
107113
urls: Optional[list[str]] = None
108-
upvote: Optional[float] = None
109-
downvote: Optional[float] = None
110-
revised_answer: Optional[str] = None
111-
feed_back_status: Optional[Literal['PENDING', 'RUNNING', 'COMPLETE', 'FAILED']] = (
112-
None
113-
)
114+
feedback: Optional[Feedback] = None
114115

115116

116117
class ChatDetails(BaseModel):
@@ -131,12 +132,6 @@ class ChatUpdate(BaseModel):
131132
title: Optional[str] = None
132133

133134

134-
class Feedback(BaseModel):
135-
upvote: Optional[int] = None
136-
downvote: Optional[int] = None
137-
revised_answer: Optional[str] = None
138-
139-
140135
class Local(BaseModel):
141136
path: Optional[str] = None
142137

aperag/views/utils.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ async def query_chat_messages(user: str, chat_id: str) -> list[view_models.ChatM
7272
msg.urls = item.get("urls", [])
7373
feedback = feedback_map.get(item.get("id", ""), None)
7474
if role == "ai" and feedback:
75-
msg.upvote = feedback.upvote
76-
msg.downvote = feedback.downvote
77-
msg.revised_answer = feedback.revised_answer
78-
msg.feed_back_status = feedback.status
75+
msg.feedback = view_models.Feedback(
76+
type=feedback.type,
77+
tag=feedback.tag,
78+
message=feedback.message
79+
)
7980
messages.append(msg)
8081
return messages
8182

aperag/views/web.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ async def feedback_message(request, bot_id: str, chat_id: str, message_id: str,
126126
if chat is None:
127127
return fail(HTTPStatus.NOT_FOUND, "Chat not found")
128128

129-
await aperag.chat.message.feedback_message(chat.user, chat_id, message_id, msg_in.upvote, msg_in.downvote)
129+
await aperag.chat.message.feedback_message(chat.user, chat_id, message_id, msg_in.type, msg_in.tag, msg_in.message)
130130
return success({})
131131

132132

0 commit comments

Comments
 (0)