修改rlhf

This commit is contained in:
jlj 2025-06-10 18:18:28 +08:00
parent 6a0ae5b132
commit 954e314afe
7 changed files with 951 additions and 839 deletions

View File

@ -1,24 +1,40 @@
from django.contrib import admin from django.contrib import admin
from .models import ( from .models import (
Conversation, Message, Feedback, FeedbackTag, DetailedFeedback, RLHFConversation, NegotiationChat, ChatHistory, Feedback, FeedbackTag, DetailedFeedback,
ConversationSubmission, ConversationEvaluation, SystemConfig ConversationSubmission, ConversationEvaluation, SystemConfig
) )
@admin.register(Conversation) @admin.register(RLHFConversation)
class ConversationAdmin(admin.ModelAdmin): class RLHFConversationAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'is_submitted', 'created_at') list_display = ('negotiation_chat', 'id', 'user', 'is_submitted', 'created_at')
list_filter = ('is_submitted', 'created_at') list_filter = ('is_submitted',)
search_fields = ('id', 'user__username') search_fields = ('negotiation_chat__conversation_id', 'negotiation_chat__negotiation__user__username')
def id(self, obj):
return obj.negotiation_chat.conversation_id
def user(self, obj):
return obj.negotiation_chat.negotiation.user
def created_at(self, obj):
return obj.negotiation_chat.created_at
@admin.register(NegotiationChat)
class NegotiationChatAdmin(admin.ModelAdmin):
list_display = ('conversation_id', 'negotiation', 'creator', 'product', 'created_at', 'updated_at')
list_filter = ('created_at', 'updated_at')
search_fields = ('conversation_id', 'negotiation__user__username', 'creator__name', 'product__name')
date_hierarchy = 'created_at' date_hierarchy = 'created_at'
@admin.register(Message) @admin.register(ChatHistory)
class MessageAdmin(admin.ModelAdmin): class ChatHistoryAdmin(admin.ModelAdmin):
list_display = ('id', 'conversation', 'role', 'short_content', 'timestamp') list_display = ('id', 'conversation_id', 'user', 'role', 'short_content', 'created_at')
list_filter = ('role', 'timestamp') list_filter = ('role', 'created_at')
search_fields = ('id', 'conversation__id', 'content') search_fields = ('id', 'conversation_id', 'content')
date_hierarchy = 'timestamp' date_hierarchy = 'created_at'
def short_content(self, obj): def short_content(self, obj):
return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content
@ -27,9 +43,9 @@ class MessageAdmin(admin.ModelAdmin):
@admin.register(Feedback) @admin.register(Feedback)
class FeedbackAdmin(admin.ModelAdmin): class FeedbackAdmin(admin.ModelAdmin):
list_display = ('id', 'message', 'conversation', 'user', 'feedback_value', 'timestamp') list_display = ('id', 'message', 'conversation_id', 'user', 'feedback_value', 'timestamp')
list_filter = ('feedback_value', 'timestamp') list_filter = ('feedback_value', 'timestamp')
search_fields = ('id', 'message__id', 'conversation__id', 'user__username') search_fields = ('id', 'message__id', 'conversation_id', 'user__username')
date_hierarchy = 'timestamp' date_hierarchy = 'timestamp'
@ -42,25 +58,25 @@ class FeedbackTagAdmin(admin.ModelAdmin):
@admin.register(DetailedFeedback) @admin.register(DetailedFeedback)
class DetailedFeedbackAdmin(admin.ModelAdmin): class DetailedFeedbackAdmin(admin.ModelAdmin):
list_display = ('id', 'message', 'conversation', 'user', 'feedback_type', 'is_inline', 'created_at') list_display = ('id', 'message', 'conversation_id', 'user', 'feedback_type', 'is_inline', 'created_at')
list_filter = ('feedback_type', 'is_inline', 'created_at') list_filter = ('feedback_type', 'is_inline', 'created_at')
search_fields = ('id', 'message__id', 'conversation__id', 'user__username', 'custom_content') search_fields = ('id', 'message__id', 'conversation_id', 'user__username', 'custom_content')
date_hierarchy = 'created_at' date_hierarchy = 'created_at'
@admin.register(ConversationSubmission) @admin.register(ConversationSubmission)
class ConversationSubmissionAdmin(admin.ModelAdmin): class ConversationSubmissionAdmin(admin.ModelAdmin):
list_display = ('id', 'conversation', 'user', 'title', 'status', 'quality_score', 'reviewer', 'submitted_at', 'reviewed_at') list_display = ('id', 'conversation_id', 'user', 'title', 'status', 'quality_score', 'reviewer', 'submitted_at', 'reviewed_at')
list_filter = ('status', 'quality_score', 'submitted_at', 'reviewed_at') list_filter = ('status', 'quality_score', 'submitted_at', 'reviewed_at')
search_fields = ('id', 'conversation__id', 'user__username', 'title', 'description', 'reviewer__username') search_fields = ('id', 'conversation_id', 'user__username', 'title', 'description', 'reviewer__username')
date_hierarchy = 'submitted_at' date_hierarchy = 'submitted_at'
@admin.register(ConversationEvaluation) @admin.register(ConversationEvaluation)
class ConversationEvaluationAdmin(admin.ModelAdmin): class ConversationEvaluationAdmin(admin.ModelAdmin):
list_display = ('id', 'conversation', 'user', 'has_logical_issues', 'needs_satisfied', 'created_at') list_display = ('id', 'conversation_id', 'user', 'has_logical_issues', 'needs_satisfied', 'created_at')
list_filter = ('has_logical_issues', 'needs_satisfied', 'created_at') list_filter = ('has_logical_issues', 'needs_satisfied', 'created_at')
search_fields = ('id', 'conversation__id', 'user__username', 'overall_feeling') search_fields = ('id', 'conversation_id', 'user__username', 'overall_feeling')
date_hierarchy = 'created_at' date_hierarchy = 'created_at'

View File

@ -1,4 +1,4 @@
# Generated by Django 5.1.5 on 2025-06-09 08:28 # Generated by Django 5.2.1 on 2025-06-10 08:10
import django.db.models.deletion import django.db.models.deletion
import django.utils.timezone import django.utils.timezone
@ -12,6 +12,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('chat', '0002_negotiationchat'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]
@ -30,6 +31,17 @@ class Migration(migrations.Migration):
'verbose_name_plural': '反馈标签', 'verbose_name_plural': '反馈标签',
}, },
), ),
migrations.CreateModel(
name='RLHFConversation',
fields=[
('negotiation_chat', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='rlhf_extension', serialize=False, to='chat.negotiationchat')),
('is_submitted', models.BooleanField(default=False)),
],
options={
'verbose_name': 'RLHF对话',
'verbose_name_plural': 'RLHF对话',
},
),
migrations.CreateModel( migrations.CreateModel(
name='SystemConfig', name='SystemConfig',
fields=[ fields=[
@ -46,23 +58,11 @@ class Migration(migrations.Migration):
'verbose_name_plural': '系统配置', 'verbose_name_plural': '系统配置',
}, },
), ),
migrations.CreateModel(
name='Conversation',
fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('is_submitted', models.BooleanField(default=False)),
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversations', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': '对话',
'verbose_name_plural': '对话',
},
),
migrations.CreateModel( migrations.CreateModel(
name='ConversationSubmission', name='ConversationSubmission',
fields=[ fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)), ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('conversation_id', models.CharField(max_length=100)),
('title', models.CharField(blank=True, max_length=255, null=True)), ('title', models.CharField(blank=True, max_length=255, null=True)),
('description', models.TextField(blank=True, null=True)), ('description', models.TextField(blank=True, null=True)),
('status', models.CharField(choices=[('submitted', '已提交'), ('reviewed', '已审核'), ('accepted', '已接受'), ('rejected', '已拒绝')], default='submitted', max_length=20)), ('status', models.CharField(choices=[('submitted', '已提交'), ('reviewed', '已审核'), ('accepted', '已接受'), ('rejected', '已拒绝')], default='submitted', max_length=20)),
@ -72,7 +72,6 @@ class Migration(migrations.Migration):
('reviewed_at', models.DateTimeField(blank=True, null=True)), ('reviewed_at', models.DateTimeField(blank=True, null=True)),
('created_at', models.DateTimeField(default=django.utils.timezone.now)), ('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('updated_at', models.DateTimeField(default=django.utils.timezone.now)), ('updated_at', models.DateTimeField(default=django.utils.timezone.now)),
('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to='rlhf.conversation')),
('reviewer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='reviewed_submissions', to=settings.AUTH_USER_MODEL)), ('reviewer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='reviewed_submissions', to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='submissions', to=settings.AUTH_USER_MODEL)),
], ],
@ -81,40 +80,11 @@ class Migration(migrations.Migration):
'verbose_name_plural': '对话提交', 'verbose_name_plural': '对话提交',
}, },
), ),
migrations.CreateModel(
name='Message',
fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('role', models.CharField(choices=[('user', '用户'), ('assistant', '助手'), ('system', '系统')], max_length=20)),
('content', models.TextField()),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='rlhf.conversation')),
],
options={
'verbose_name': '消息',
'verbose_name_plural': '消息',
'ordering': ['timestamp'],
},
),
migrations.CreateModel(
name='Feedback',
fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('feedback_value', models.IntegerField()),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedback', to='rlhf.conversation')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedback', to=settings.AUTH_USER_MODEL)),
('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedback', to='rlhf.message')),
],
options={
'verbose_name': '反馈',
'verbose_name_plural': '反馈',
},
),
migrations.CreateModel( migrations.CreateModel(
name='DetailedFeedback', name='DetailedFeedback',
fields=[ fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)), ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('conversation_id', models.CharField(max_length=100)),
('feedback_type', models.CharField(choices=[('positive', '正面'), ('negative', '负面'), ('neutral', '中性')], max_length=20)), ('feedback_type', models.CharField(choices=[('positive', '正面'), ('negative', '负面'), ('neutral', '中性')], max_length=20)),
('feedback_tags', models.TextField(blank=True, null=True)), ('feedback_tags', models.TextField(blank=True, null=True)),
('custom_tags', models.TextField(blank=True, null=True)), ('custom_tags', models.TextField(blank=True, null=True)),
@ -122,31 +92,45 @@ class Migration(migrations.Migration):
('is_inline', models.BooleanField(default=True)), ('is_inline', models.BooleanField(default=True)),
('created_at', models.DateTimeField(default=django.utils.timezone.now)), ('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('updated_at', models.DateTimeField(default=django.utils.timezone.now)), ('updated_at', models.DateTimeField(default=django.utils.timezone.now)),
('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='detailed_feedback', to='rlhf.conversation')), ('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rlhf_detailed_feedback', to='chat.chathistory')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='detailed_feedback', to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='detailed_feedback', to=settings.AUTH_USER_MODEL)),
('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='detailed_feedback', to='rlhf.message')),
], ],
options={ options={
'verbose_name': '详细反馈', 'verbose_name': '详细反馈',
'verbose_name_plural': '详细反馈', 'verbose_name_plural': '详细反馈',
}, },
), ),
migrations.CreateModel(
name='Feedback',
fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('conversation_id', models.CharField(max_length=100)),
('feedback_value', models.IntegerField()),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('message', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rlhf_feedback', to='chat.chathistory')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='feedback', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': '反馈',
'verbose_name_plural': '反馈',
},
),
migrations.CreateModel( migrations.CreateModel(
name='ConversationEvaluation', name='ConversationEvaluation',
fields=[ fields=[
('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)), ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=36, primary_key=True, serialize=False)),
('conversation_id', models.CharField(max_length=100)),
('overall_feeling', models.TextField(blank=True, null=True)), ('overall_feeling', models.TextField(blank=True, null=True)),
('has_logical_issues', models.CharField(choices=[('yes', ''), ('no', ''), ('unsure', '不确定')], max_length=10)), ('has_logical_issues', models.CharField(choices=[('yes', ''), ('no', ''), ('unsure', '不确定')], max_length=10)),
('needs_satisfied', models.CharField(choices=[('yes', ''), ('no', ''), ('partially', '部分')], max_length=10)), ('needs_satisfied', models.CharField(choices=[('yes', ''), ('no', ''), ('partially', '部分')], max_length=10)),
('created_at', models.DateTimeField(default=django.utils.timezone.now)), ('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('updated_at', models.DateTimeField(default=django.utils.timezone.now)), ('updated_at', models.DateTimeField(default=django.utils.timezone.now)),
('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='evaluations', to='rlhf.conversation')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='evaluations', to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='evaluations', to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'verbose_name': '对话评估', 'verbose_name': '对话评估',
'verbose_name_plural': '对话评估', 'verbose_name_plural': '对话评估',
'unique_together': {('conversation', 'user')}, 'unique_together': {('conversation_id', 'user')},
}, },
), ),
] ]

View File

@ -2,60 +2,91 @@ from django.db import models
import uuid import uuid
from django.utils import timezone from django.utils import timezone
from apps.user.models import User from apps.user.models import User
from apps.chat.models import ChatHistory, NegotiationChat
from apps.daren_detail.models import CreatorProfile
from apps.brands.models import Product
class Conversation(models.Model): # 使用NegotiationChat替代Conversation
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False) # class Conversation(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='conversations') # id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False)
# user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='conversations')
# is_submitted = models.BooleanField(default=False)
# created_at = models.DateTimeField(default=timezone.now)
#
# class Meta:
# verbose_name = '对话'
# verbose_name_plural = '对话'
#
# def __str__(self):
# return f"Conversation {self.id[:8]}"
# 为NegotiationChat添加RLHF所需字段的代理模型
class RLHFConversation(models.Model):
"""对NegotiationChat的扩展添加RLHF所需字段"""
negotiation_chat = models.OneToOneField(NegotiationChat, on_delete=models.CASCADE, primary_key=True, related_name='rlhf_extension')
is_submitted = models.BooleanField(default=False) is_submitted = models.BooleanField(default=False)
created_at = models.DateTimeField(default=timezone.now)
class Meta: class Meta:
verbose_name = '对话' verbose_name = 'RLHF对话'
verbose_name_plural = '对话' verbose_name_plural = 'RLHF对话'
def __str__(self): def __str__(self):
return f"Conversation {self.id[:8]}" return f"RLHF Conversation {self.negotiation_chat.conversation_id[:8]}"
@property
def id(self):
return self.negotiation_chat.conversation_id
@property
def user(self):
# 从谈判关联的用户中获取
return self.negotiation_chat.negotiation.user
@property
def created_at(self):
return self.negotiation_chat.created_at
class Message(models.Model): # 使用ChatHistory替代Message
ROLE_CHOICES = ( # class Message(models.Model):
('user', '用户'), # ROLE_CHOICES = (
('assistant', '助手'), # ('user', '用户'),
('system', '系统'), # ('assistant', '助手'),
) # ('system', '系统'),
# )
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False) #
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='messages') # id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False)
role = models.CharField(max_length=20, choices=ROLE_CHOICES) # conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='messages')
content = models.TextField() # role = models.CharField(max_length=20, choices=ROLE_CHOICES)
timestamp = models.DateTimeField(default=timezone.now) # content = models.TextField()
# timestamp = models.DateTimeField(default=timezone.now)
class Meta: #
# class Meta:
verbose_name = '消息' #
verbose_name_plural = '消息' # verbose_name = '消息'
ordering = ['timestamp'] # verbose_name_plural = '消息'
# ordering = ['timestamp']
def __str__(self): #
return f"{self.role}: {self.content[:50]}..." # def __str__(self):
# return f"{self.role}: {self.content[:50]}..."
class Feedback(models.Model): class Feedback(models.Model):
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False) id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False)
message = models.ForeignKey(Message, on_delete=models.CASCADE, related_name='feedback') message = models.ForeignKey(ChatHistory, on_delete=models.CASCADE, related_name='rlhf_feedback')
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='feedback') conversation_id = models.CharField(max_length=100) # 存储NegotiationChat的conversation_id
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='feedback') user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='feedback')
feedback_value = models.IntegerField() feedback_value = models.IntegerField()
timestamp = models.DateTimeField(default=timezone.now) timestamp = models.DateTimeField(default=timezone.now)
class Meta: class Meta:
verbose_name = '反馈' verbose_name = '反馈'
verbose_name_plural = '反馈' verbose_name_plural = '反馈'
def __str__(self): def __str__(self):
return f"Feedback on {self.message.id[:8]}" return f"Feedback on {self.message.id}"
class FeedbackTag(models.Model): class FeedbackTag(models.Model):
@ -71,7 +102,6 @@ class FeedbackTag(models.Model):
created_at = models.DateTimeField(default=timezone.now) created_at = models.DateTimeField(default=timezone.now)
class Meta: class Meta:
verbose_name = '反馈标签' verbose_name = '反馈标签'
verbose_name_plural = '反馈标签' verbose_name_plural = '反馈标签'
@ -87,8 +117,8 @@ class DetailedFeedback(models.Model):
) )
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False) id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False)
message = models.ForeignKey(Message, on_delete=models.CASCADE, related_name='detailed_feedback') message = models.ForeignKey(ChatHistory, on_delete=models.CASCADE, related_name='rlhf_detailed_feedback')
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='detailed_feedback') conversation_id = models.CharField(max_length=100) # 存储NegotiationChat的conversation_id
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='detailed_feedback') user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='detailed_feedback')
feedback_type = models.CharField(max_length=20, choices=FEEDBACK_TYPE_CHOICES) feedback_type = models.CharField(max_length=20, choices=FEEDBACK_TYPE_CHOICES)
feedback_tags = models.TextField(blank=True, null=True) # JSON格式存储多个标签 feedback_tags = models.TextField(blank=True, null=True) # JSON格式存储多个标签
@ -99,12 +129,11 @@ class DetailedFeedback(models.Model):
updated_at = models.DateTimeField(default=timezone.now) updated_at = models.DateTimeField(default=timezone.now)
class Meta: class Meta:
verbose_name = '详细反馈' verbose_name = '详细反馈'
verbose_name_plural = '详细反馈' verbose_name_plural = '详细反馈'
def __str__(self): def __str__(self):
return f"{self.feedback_type} feedback on {self.message.id[:8]}" return f"{self.feedback_type} feedback on {self.message.id}"
class ConversationSubmission(models.Model): class ConversationSubmission(models.Model):
@ -116,7 +145,7 @@ class ConversationSubmission(models.Model):
) )
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False) id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False)
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='submissions') conversation_id = models.CharField(max_length=100) # 存储NegotiationChat的conversation_id
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='submissions') user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='submissions')
title = models.CharField(max_length=255, blank=True, null=True) title = models.CharField(max_length=255, blank=True, null=True)
description = models.TextField(blank=True, null=True) description = models.TextField(blank=True, null=True)
@ -130,12 +159,11 @@ class ConversationSubmission(models.Model):
updated_at = models.DateTimeField(default=timezone.now) updated_at = models.DateTimeField(default=timezone.now)
class Meta: class Meta:
verbose_name = '对话提交' verbose_name = '对话提交'
verbose_name_plural = '对话提交' verbose_name_plural = '对话提交'
def __str__(self): def __str__(self):
return f"Submission for {self.conversation.id[:8]}" return f"Submission for {self.conversation_id[:8]}"
class ConversationEvaluation(models.Model): class ConversationEvaluation(models.Model):
@ -152,7 +180,7 @@ class ConversationEvaluation(models.Model):
) )
id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False) id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4, editable=False)
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, related_name='evaluations') conversation_id = models.CharField(max_length=100) # 存储NegotiationChat的conversation_id
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='evaluations') user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='evaluations')
overall_feeling = models.TextField(blank=True, null=True) overall_feeling = models.TextField(blank=True, null=True)
has_logical_issues = models.CharField(max_length=10, choices=LOGICAL_CHOICES) has_logical_issues = models.CharField(max_length=10, choices=LOGICAL_CHOICES)
@ -161,13 +189,12 @@ class ConversationEvaluation(models.Model):
updated_at = models.DateTimeField(default=timezone.now) updated_at = models.DateTimeField(default=timezone.now)
class Meta: class Meta:
verbose_name = '对话评估' verbose_name = '对话评估'
verbose_name_plural = '对话评估' verbose_name_plural = '对话评估'
unique_together = ('conversation', 'user') unique_together = ('conversation_id', 'user')
def __str__(self): def __str__(self):
return f"Evaluation for {self.conversation.id[:8]}" return f"Evaluation for {self.conversation_id[:8]}"
class SystemConfig(models.Model): class SystemConfig(models.Model):

View File

@ -1,29 +1,43 @@
from rest_framework import serializers from rest_framework import serializers
from .models import ( from .models import (
Conversation, Message, Feedback, FeedbackTag, DetailedFeedback, Feedback, FeedbackTag, DetailedFeedback,
ConversationSubmission, ConversationEvaluation, SystemConfig ConversationSubmission, ConversationEvaluation, SystemConfig,
RLHFConversation, NegotiationChat, ChatHistory
) )
from apps.user.serializers import UserSerializer from apps.user.serializers import UserSerializer
class ConversationSerializer(serializers.ModelSerializer): class ConversationSerializer(serializers.ModelSerializer):
id = serializers.CharField(source='conversation_id', read_only=True)
user = serializers.PrimaryKeyRelatedField(source='negotiation.user', read_only=True)
is_submitted = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(source='created_at', read_only=True)
class Meta: class Meta:
model = Conversation model = NegotiationChat
fields = ['id', 'user', 'is_submitted', 'created_at'] fields = ['id', 'user', 'is_submitted', 'created_at']
read_only_fields = ['id', 'created_at', 'user']
def get_is_submitted(self, obj):
# 尝试获取RLHF扩展
try:
return obj.rlhf_extension.is_submitted
except RLHFConversation.DoesNotExist:
return False
class MessageSerializer(serializers.ModelSerializer): class MessageSerializer(serializers.ModelSerializer):
conversation = serializers.CharField(source='conversation_id', read_only=True)
timestamp = serializers.DateTimeField(source='created_at', read_only=True)
class Meta: class Meta:
model = Message model = ChatHistory
fields = ['id', 'conversation', 'role', 'content', 'timestamp'] fields = ['id', 'conversation', 'role', 'content', 'timestamp']
read_only_fields = ['id', 'timestamp']
class FeedbackSerializer(serializers.ModelSerializer): class FeedbackSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Feedback model = Feedback
fields = ['id', 'message', 'conversation', 'user', 'feedback_value', 'timestamp'] fields = ['id', 'message', 'conversation_id', 'user', 'feedback_value', 'timestamp']
read_only_fields = ['id', 'timestamp'] read_only_fields = ['id', 'timestamp']
@ -37,7 +51,11 @@ class FeedbackTagSerializer(serializers.ModelSerializer):
class DetailedFeedbackSerializer(serializers.ModelSerializer): class DetailedFeedbackSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = DetailedFeedback model = DetailedFeedback
fields = ['id', 'message', 'conversation', 'user', 'feedback_type', 'feedback_tags', 'custom_tags', 'custom_content', 'is_inline', 'created_at', 'updated_at'] fields = [
'id', 'message', 'conversation_id', 'user', 'feedback_type',
'feedback_tags', 'custom_tags', 'custom_content', 'is_inline',
'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at']
@ -47,38 +65,72 @@ class ConversationSubmissionSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ConversationSubmission model = ConversationSubmission
fields = ['id', 'conversation', 'user', 'user_details', 'title', 'description', 'status', 'quality_score', 'reviewer', 'reviewer_details', 'reviewer_notes', 'submitted_at', 'reviewed_at', 'created_at', 'updated_at'] fields = [
'id', 'conversation_id', 'user', 'title', 'description',
'status', 'quality_score', 'reviewer', 'reviewer_details',
'reviewer_notes', 'submitted_at', 'reviewed_at', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'submitted_at', 'reviewed_at', 'created_at', 'updated_at'] read_only_fields = ['id', 'submitted_at', 'reviewed_at', 'created_at', 'updated_at']
class ConversationEvaluationSerializer(serializers.ModelSerializer): class ConversationEvaluationSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ConversationEvaluation model = ConversationEvaluation
fields = ['id', 'conversation', 'user', 'overall_feeling', 'has_logical_issues', 'needs_satisfied', 'created_at', 'updated_at'] fields = [
'id', 'conversation_id', 'user', 'overall_feeling',
'has_logical_issues', 'needs_satisfied', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at']
class SystemConfigSerializer(serializers.ModelSerializer): class SystemConfigSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = SystemConfig model = SystemConfig
fields = ['id', 'config_key', 'config_value', 'config_type', 'description', 'created_at', 'updated_at'] fields = [
'id', 'config_key', 'config_value', 'config_type',
'description', 'created_at', 'updated_at'
]
read_only_fields = ['id', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at']
class ConversationWithMessagesSerializer(serializers.ModelSerializer): class ConversationWithMessagesSerializer(serializers.ModelSerializer):
messages = MessageSerializer(many=True, read_only=True) id = serializers.CharField(source='conversation_id', read_only=True)
user = serializers.PrimaryKeyRelatedField(source='negotiation.user', read_only=True)
is_submitted = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(source='created_at', read_only=True)
messages = serializers.SerializerMethodField()
class Meta: class Meta:
model = Conversation model = NegotiationChat
fields = ['id', 'user', 'is_submitted', 'created_at', 'messages'] fields = ['id', 'user', 'is_submitted', 'created_at', 'messages']
read_only_fields = ['id', 'created_at']
def get_is_submitted(self, obj):
try:
return obj.rlhf_extension.is_submitted
except RLHFConversation.DoesNotExist:
return False
def get_messages(self, obj):
messages = ChatHistory.objects.filter(
conversation_id=obj.conversation_id
).order_by('created_at')
return MessageSerializer(messages, many=True).data
class MessageWithFeedbackSerializer(serializers.ModelSerializer): class MessageWithFeedbackSerializer(serializers.ModelSerializer):
feedback = FeedbackSerializer(many=True, read_only=True) conversation = serializers.CharField(source='conversation_id', read_only=True)
detailed_feedback = DetailedFeedbackSerializer(many=True, read_only=True) timestamp = serializers.DateTimeField(source='created_at', read_only=True)
feedback = serializers.SerializerMethodField()
detailed_feedback = serializers.SerializerMethodField()
class Meta: class Meta:
model = Message model = ChatHistory
fields = ['id', 'conversation', 'role', 'content', 'timestamp', 'feedback', 'detailed_feedback'] fields = ['id', 'conversation', 'role', 'content', 'timestamp', 'feedback', 'detailed_feedback']
read_only_fields = ['id', 'timestamp']
def get_feedback(self, obj):
feedback = Feedback.objects.filter(message=obj)
return FeedbackSerializer(feedback, many=True).data
def get_detailed_feedback(self, obj):
detailed_feedback = DetailedFeedback.objects.filter(message=obj)
return DetailedFeedbackSerializer(detailed_feedback, many=True).data

View File

@ -5,8 +5,9 @@ from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination from rest_framework.pagination import PageNumberPagination
from .models import ( from .models import (
Conversation, Message, Feedback, FeedbackTag, DetailedFeedback, Feedback, FeedbackTag, DetailedFeedback,
ConversationSubmission, ConversationEvaluation, SystemConfig ConversationSubmission, ConversationEvaluation, SystemConfig,
NegotiationChat, ChatHistory, RLHFConversation, CreatorProfile, Product
) )
from .serializers import ( from .serializers import (
ConversationSerializer, MessageSerializer, FeedbackSerializer, ConversationSerializer, MessageSerializer, FeedbackSerializer,
@ -98,22 +99,44 @@ class StandardResponseMixin:
class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet): class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
queryset = Conversation.objects.all() queryset = NegotiationChat.objects.all()
serializer_class = ConversationSerializer serializer_class = ConversationSerializer
authentication_classes = [CustomTokenAuthentication] authentication_classes = [CustomTokenAuthentication]
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
return Conversation.objects.filter(user=user).order_by('-created_at') return NegotiationChat.objects.filter(negotiation__user=user).order_by('-updated_at')
def perform_create(self, serializer): def perform_create(self, serializer):
serializer.save(user=self.request.user) creator = CreatorProfile.objects.first()
product = Product.objects.first()
negotiation = Negotiation.objects.create(
user=self.request.user,
status='active'
)
chat = NegotiationChat.objects.create(
negotiation=negotiation,
conversation_id=str(uuid.uuid4()),
creator=creator,
product=product
)
RLHFConversation.objects.create(
negotiation_chat=chat,
is_submitted=False
)
serializer.instance = chat
@action(detail=True, methods=['get']) @action(detail=True, methods=['get'])
def messages(self, request, pk=None): def messages(self, request, pk=None):
conversation = self.get_object() conversation = self.get_object()
messages = Message.objects.filter(conversation=conversation).order_by('timestamp') messages = ChatHistory.objects.filter(
conversation_id=conversation.conversation_id
).order_by('created_at')
serializer = MessageSerializer(messages, many=True) serializer = MessageSerializer(messages, many=True)
return self.get_standard_response(data=serializer.data) return self.get_standard_response(data=serializer.data)
@ -130,27 +153,26 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
status_code=status.HTTP_400_BAD_REQUEST status_code=status.HTTP_400_BAD_REQUEST
) )
# 创建用户消息 knowledge_base = KnowledgeBase.objects.first()
user_message = Message.objects.create(
id=str(uuid.uuid4()), user_message = ChatHistory.objects.create(
conversation=conversation, user=request.user,
knowledge_base=knowledge_base,
conversation_id=conversation.conversation_id,
role='user', role='user',
content=content content=content
) )
# 这里需要调用AI服务获取回复 ai_response = self._generate_ai_response(content, conversation)
# 示例调用SiliconFlow或其他AI服务
ai_response = self._generate_ai_response(user_message.content, conversation)
# 创建AI回复消息 ai_message = ChatHistory.objects.create(
ai_message = Message.objects.create( user=request.user,
id=str(uuid.uuid4()), knowledge_base=knowledge_base,
conversation=conversation, conversation_id=conversation.conversation_id,
role='assistant', role='assistant',
content=ai_response content=ai_response
) )
# 更新用户的标注统计
self._update_annotation_stats(request.user.id) self._update_annotation_stats(request.user.id)
messages = [ messages = [
@ -166,7 +188,12 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
title = request.data.get('title', '') title = request.data.get('title', '')
description = request.data.get('description', '') description = request.data.get('description', '')
if conversation.is_submitted: rlhf_conv, created = RLHFConversation.objects.get_or_create(
negotiation_chat=conversation,
defaults={'is_submitted': False}
)
if rlhf_conv.is_submitted:
return self.get_standard_response( return self.get_standard_response(
code=400, code=400,
message='该对话已提交', message='该对话已提交',
@ -174,14 +201,12 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
status_code=status.HTTP_400_BAD_REQUEST status_code=status.HTTP_400_BAD_REQUEST
) )
# 更新对话为已提交状态 rlhf_conv.is_submitted = True
conversation.is_submitted = True rlhf_conv.save()
conversation.save()
# 创建提交记录
submission = ConversationSubmission.objects.create( submission = ConversationSubmission.objects.create(
id=str(uuid.uuid4()), id=str(uuid.uuid4()),
conversation=conversation, conversation_id=conversation.conversation_id,
user=request.user, user=request.user,
title=title, title=title,
description=description, description=description,
@ -189,12 +214,11 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
submitted_at=timezone.now() submitted_at=timezone.now()
) )
# 记录活动日志
UserActivityLog.objects.create( UserActivityLog.objects.create(
user=request.user, user=request.user,
action_type='conversation_submit', action_type='conversation_submit',
target_type='conversation', target_type='conversation',
target_id=str(conversation.id), target_id=conversation.conversation_id,
details={'title': title} details={'title': title}
) )
@ -207,7 +231,12 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
def resume(self, request, pk=None): def resume(self, request, pk=None):
conversation = self.get_object() conversation = self.get_object()
if not conversation.is_submitted: rlhf_conv, created = RLHFConversation.objects.get_or_create(
negotiation_chat=conversation,
defaults={'is_submitted': False}
)
if not rlhf_conv.is_submitted:
return self.get_standard_response( return self.get_standard_response(
code=400, code=400,
message='该对话未提交,无需恢复', message='该对话未提交,无需恢复',
@ -215,25 +244,22 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
status_code=status.HTTP_400_BAD_REQUEST status_code=status.HTTP_400_BAD_REQUEST
) )
# 更新对话为未提交状态 rlhf_conv.is_submitted = False
conversation.is_submitted = False rlhf_conv.save()
conversation.save()
# 获取最新的提交记录
submission = ConversationSubmission.objects.filter( submission = ConversationSubmission.objects.filter(
conversation=conversation conversation_id=conversation.conversation_id
).order_by('-submitted_at').first() ).order_by('-submitted_at').first()
if submission and submission.status == 'submitted': if submission and submission.status == 'submitted':
submission.status = 'rejected' submission.status = 'rejected'
submission.save() submission.save()
# 记录活动日志
UserActivityLog.objects.create( UserActivityLog.objects.create(
user=request.user, user=request.user,
action_type='conversation_resume', action_type='conversation_resume',
target_type='conversation', target_type='conversation',
target_id=str(conversation.id) target_id=conversation.conversation_id
) )
return self.get_standard_response( return self.get_standard_response(
@ -264,7 +290,7 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
sf_client.set_system_message(system_prompt_config.config_value) sf_client.set_system_message(system_prompt_config.config_value)
# 获取历史消息作为上下文 # 获取历史消息作为上下文
history_messages = Message.objects.filter(conversation=conversation).order_by('timestamp') history_messages = ChatHistory.objects.filter(conversation_id=conversation.conversation_id).order_by('created_at')
# 添加历史消息到客户端 # 添加历史消息到客户端
for msg in history_messages: for msg in history_messages:
@ -385,28 +411,28 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
def _get_recent_conversations(self, user_id, limit=5): def _get_recent_conversations(self, user_id, limit=5):
"""获取用户最近的对话""" """获取用户最近的对话"""
conversations = Conversation.objects.filter( conversations = NegotiationChat.objects.filter(
user_id=user_id negotiation__user_id=user_id
).order_by('-created_at')[:limit] ).order_by('-updated_at')[:limit]
result = [] result = []
for conv in conversations: for conv in conversations:
# 获取最后一条消息内容作为对话摘要 # 获取最后一条消息内容作为对话摘要
last_message = Message.objects.filter( last_message = ChatHistory.objects.filter(
conversation_id=conv.id conversation_id=conv.conversation_id
).order_by('-timestamp').first() ).order_by('-created_at').first()
# 统计消息数 # 统计消息数
message_count = Message.objects.filter(conversation_id=conv.id).count() message_count = ChatHistory.objects.filter(conversation_id=conv.conversation_id).count()
# 统计反馈数 # 统计反馈数
feedback_count = Feedback.objects.filter(conversation_id=conv.id).count() feedback_count = Feedback.objects.filter(conversation_id=conv.conversation_id).count()
detailed_count = DetailedFeedback.objects.filter(conversation_id=conv.id).count() detailed_count = DetailedFeedback.objects.filter(conversation_id=conv.conversation_id).count()
result.append({ result.append({
'id': str(conv.id), 'id': str(conv.conversation_id),
'created_at': conv.created_at.isoformat(), 'created_at': conv.updated_at.isoformat(),
'is_submitted': conv.is_submitted, 'is_submitted': conv.negotiation.is_submitted,
'message_count': message_count, 'message_count': message_count,
'feedback_count': feedback_count + detailed_count, 'feedback_count': feedback_count + detailed_count,
'summary': last_message.content[:100] + "..." if last_message and len(last_message.content) > 100 else (last_message.content if last_message else "") 'summary': last_message.content[:100] + "..." if last_message and len(last_message.content) > 100 else (last_message.content if last_message else "")
@ -416,12 +442,12 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
def _get_conversation_stats(self, user_id): def _get_conversation_stats(self, user_id):
"""获取对话统计""" """获取对话统计"""
total_conversations = Conversation.objects.filter(user_id=user_id).count() total_conversations = NegotiationChat.objects.filter(negotiation__user_id=user_id).count()
submitted_conversations = Conversation.objects.filter(user_id=user_id, is_submitted=True).count() submitted_conversations = NegotiationChat.objects.filter(negotiation__user_id=user_id, negotiation__is_submitted=True).count()
# 对话消息统计 # 对话消息统计
message_stats = Message.objects.filter( message_stats = ChatHistory.objects.filter(
conversation__user_id=user_id conversation__negotiation__user_id=user_id
).aggregate( ).aggregate(
total=Count('id'), total=Count('id'),
user_messages=Count('id', filter=Q(role='user')), user_messages=Count('id', filter=Q(role='user')),
@ -620,14 +646,21 @@ class ConversationViewSet(StandardResponseMixin, viewsets.ModelViewSet):
class MessageViewSet(StandardResponseMixin, viewsets.ModelViewSet): class MessageViewSet(StandardResponseMixin, viewsets.ModelViewSet):
queryset = Message.objects.all() queryset = ChatHistory.objects.all()
serializer_class = MessageSerializer serializer_class = MessageSerializer
authentication_classes = [CustomTokenAuthentication] authentication_classes = [CustomTokenAuthentication]
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
def get_queryset(self): def get_queryset(self):
user = self.request.user user = self.request.user
return Message.objects.filter(conversation__user=user).order_by('timestamp') # 获取用户参与的所有对话的ID
user_conversation_ids = NegotiationChat.objects.filter(
negotiation__user=user
).values_list('conversation_id', flat=True)
# 筛选这些对话中的消息
return ChatHistory.objects.filter(
conversation_id__in=user_conversation_ids
).order_by('created_at')
class FeedbackViewSet(StandardResponseMixin, viewsets.ModelViewSet): class FeedbackViewSet(StandardResponseMixin, viewsets.ModelViewSet):