diff --git a/.claude/settings.json b/.claude/settings.json index 89f2e98..77b29a5 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -173,7 +173,35 @@ "Bash(ls c:/Users/admin/Desktop/Lila-Server/qy_lty/settings*)", "Bash(python manage.py makemigrations card)", "Bash(python manage.py runserver)", - "Bash(start cmd:*)" + "Bash(start cmd:*)", + "Bash(redis-cli ping:*)", + "Bash(where redis-cli:*)", + "Bash(cmd //c \"where redis-cli\")", + "Bash(cmd //c \"where redis-server\")", + "Read(//c//**)", + "Bash(cmd //c \"where /R C:\\\\\\\\Program Files redis-server.exe\")", + "Bash(cmd //c \"where /R C:\\\\\\\\Users\\\\\\\\admin redis-server.exe\")", + "Read(//c/Redis/**)", + "Read(//c/Program Files/Redis/**)", + "Bash(docker info:*)", + "Bash(cmd //c \"sc query Redis\")", + "Bash(conda run:*)", + "Bash(cmd //c \"conda activate fengye && pip show django-redis\")", + "Bash(conda env:*)", + "Bash(cmd //c \"conda env list\")", + "Read(//c/Users/admin/anaconda3/Scripts/**)", + "Read(//c/Users/admin/miniconda3/Scripts/**)", + "Read(//c/ProgramData/anaconda3/Scripts/**)", + "Read(//c/ProgramData/miniconda3/Scripts/**)", + "Bash(cmd //c \"where python\")", + "Bash(cmd //c \"C:\\\\python\\\\python.exe -c \\\\\"import django; print\\(django.get_version\\(\\)\\)\\\\\"\")", + "Bash(cmd //c \"C:\\\\python\\\\python.exe -m pip list\")", + "Bash(cmd //c \"netstat -ano | findstr :8000 | findstr LISTENING\")", + "Bash(cmd //c \"netstat -ano | findstr :3000 | findstr LISTENING\")", + "Bash(cmd //c \"netstat -ano | findstr LISTENING | findstr /R \\\\\"8000 3000\\\\\"\")", + "Bash(cmd //c \"netstat -ano\")", + "Bash(/c/python/python.exe -m daphne -b 0.0.0.0 -p 8000 qy_lty.asgi:application)", + "Bash(kill %1)" ], "additionalDirectories": [ "C:\\Users\\admin\\.claude" diff --git a/qy_lty/aiapp/migrations/0003_create_rtc_bot.py b/qy_lty/aiapp/migrations/0003_create_rtc_bot.py new file mode 100644 index 0000000..99455db --- /dev/null +++ b/qy_lty/aiapp/migrations/0003_create_rtc_bot.py @@ -0,0 +1,25 @@ +from django.db import migrations + + +def create_rtc_bot(apps, schema_editor): + Bot = apps.get_model('aiapp', 'Bot') + Bot.objects.get_or_create( + name='RTC_Voice_Agent', + defaults={'description': 'RTC实时语音智能体'} + ) + + +def remove_rtc_bot(apps, schema_editor): + Bot = apps.get_model('aiapp', 'Bot') + Bot.objects.filter(name='RTC_Voice_Agent').delete() + + +class Migration(migrations.Migration): + + dependencies = [ + ('aiapp', '0002_initial'), + ] + + operations = [ + migrations.RunPython(create_rtc_bot, remove_rtc_bot), + ] diff --git a/qy_lty/aiapp/urls.py b/qy_lty/aiapp/urls.py index 2f0fe30..b88f853 100644 --- a/qy_lty/aiapp/urls.py +++ b/qy_lty/aiapp/urls.py @@ -1,6 +1,6 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from .views import ChatBotAPIView, MultiChatAPIView, BotViewSet +from .views import ChatBotAPIView, MultiChatAPIView, BotViewSet, RTCChatHistoryAPIView router = DefaultRouter() router.register(r'bots', BotViewSet, basename='bot') @@ -9,4 +9,5 @@ urlpatterns = [ path('', include(router.urls)), path('chat//', ChatBotAPIView.as_view(), name='chat-bot'), path('multichat/', MultiChatAPIView.as_view(), name='multi-chat'), + path('rtc-chat-history/', RTCChatHistoryAPIView.as_view(), name='rtc-chat-history'), ] diff --git a/qy_lty/aiapp/views.py b/qy_lty/aiapp/views.py index 9543574..4ea7900 100644 --- a/qy_lty/aiapp/views.py +++ b/qy_lty/aiapp/views.py @@ -9,6 +9,7 @@ from rest_framework.permissions import IsAuthenticated from userapp.authentication import RedisTokenAuthentication from rest_framework import serializers from common.swagger_utils import swagger_schema +from common.responses import success_response, created_response, error_response from drf_yasg import openapi from drf_yasg.utils import swagger_auto_schema import logging @@ -427,4 +428,89 @@ def create_user_message(user: ParadiseUser, bot: Bot, message_type: str, user_me logger.info(f"Created video message for user {user.id} and bot {bot.id}") return user_chat_message - return None \ No newline at end of file + return None + + +class RTCChatHistoryAPIView(APIView): + """ + RTC 语音智能体聊天记录接口 + + GET: 获取当前用户的 RTC 聊天历史 + POST: 保存一条 RTC 聊天消息 + DELETE: 清空当前用户的 RTC 聊天记录 + """ + authentication_classes = [RedisTokenAuthentication] + permission_classes = [IsAuthenticated] + + RTC_BOT_NAME = 'RTC_Voice_Agent' + + def _get_rtc_bot(self): + try: + return Bot.objects.get(name=self.RTC_BOT_NAME) + except Bot.DoesNotExist: + return None + + def get(self, request): + bot = self._get_rtc_bot() + if bot is None: + return error_response(message='RTC Bot 未配置', code=500, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + page_size = int(request.query_params.get('page_size', 50)) + page_size = min(page_size, 200) + + queryset = ChatMessage.objects.filter( + user=request.user, + bot=bot + ).order_by('timestamp') + + total = queryset.count() + messages = queryset[max(0, total - page_size):] + + data = { + 'messages': [ + { + 'id': msg.id, + 'message': msg.message, + 'sender': msg.sender, + 'timestamp': msg.timestamp.isoformat(), + } + for msg in messages + ], + 'total': total, + 'has_more': total > page_size, + } + return success_response(data=data) + + def post(self, request): + bot = self._get_rtc_bot() + if bot is None: + return error_response(message='RTC Bot 未配置', code=500, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + message_text = request.data.get('message', '').strip() + sender = request.data.get('sender', '').strip() + + if not message_text: + return error_response(message='消息内容不能为空') + if sender not in ('user', 'assistant'): + return error_response(message='sender 必须是 user 或 assistant') + + chat_msg = ChatMessage.objects.create( + user=request.user, + bot=bot, + message=message_text, + sender=sender, + message_type=ChatMessage.MESSAGE_TYPE_TEXT, + ) + + return created_response(data={ + 'id': chat_msg.id, + 'timestamp': chat_msg.timestamp.isoformat(), + }) + + def delete(self, request): + bot = self._get_rtc_bot() + if bot is None: + return error_response(message='RTC Bot 未配置', code=500, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) + + count, _ = ChatMessage.objects.filter(user=request.user, bot=bot).delete() + return success_response(data={'deleted': count}, message=f'已删除 {count} 条记录') \ No newline at end of file