add prodcut ai chat bot
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
from django.contrib import admin
|
||||
from .models import *
|
||||
from unfold.admin import ModelAdmin
|
||||
|
||||
|
||||
@admin.register(ProductChatModel)
|
||||
class ProductChatAdmin(ModelAdmin):
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ChatConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'chat'
|
||||
@@ -0,0 +1,30 @@
|
||||
# Generated by Django 5.1.2 on 2025-01-01 17:58
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('product', '0005_categorymodel'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProductChatModel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('thread', models.CharField(blank=True, max_length=400, null=True)),
|
||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='product.productmodel')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('user', 'product')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,60 @@
|
||||
from django.db import models
|
||||
from account.models import User
|
||||
from product.models import ProductModel
|
||||
from django.conf import settings
|
||||
import openai
|
||||
from time import sleep
|
||||
from product.serializers import ProductChatSerializer
|
||||
|
||||
|
||||
ASSISTANT_ID = 'asst_1wOnCKncEHkOfp0FjOIz4Xkp'
|
||||
class ProductChatModel(models.Model):
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
product = models.ForeignKey(ProductModel, on_delete=models.CASCADE)
|
||||
thread = models.CharField(max_length=400, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ['user', 'product']
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.user} - {self.product}'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.thread:
|
||||
client = openai.OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||
product_json = ProductChatSerializer(instance=self.product).data
|
||||
print(product_json)
|
||||
try:
|
||||
|
||||
thread = client.beta.threads.create(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
#TODO update first message
|
||||
"content": f"this is the start of the chat greet the user this chat is about the product with given detail: {product_json}",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
run = client.beta.threads.runs.create(
|
||||
thread_id=thread.id,
|
||||
assistant_id=ASSISTANT_ID
|
||||
)
|
||||
|
||||
|
||||
while run.status != "completed":
|
||||
run = client.beta.threads.runs.retrieve(
|
||||
thread_id=thread.id,
|
||||
run_id=run.id
|
||||
)
|
||||
sleep(1)
|
||||
|
||||
|
||||
self.thread = thread.id
|
||||
|
||||
except Exception as e:
|
||||
print(f'error in chat class: {e}')
|
||||
raise ValueError(f"Error creating OpenAI thread: {e}")
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('product/<int:pk>', views.ProductChatView.as_view(), name='product-chat-view'),
|
||||
]
|
||||
@@ -0,0 +1,178 @@
|
||||
from django.core.paginator import Paginator
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.db.models import Q
|
||||
from time import sleep
|
||||
import json
|
||||
from drf_spectacular.utils import (
|
||||
extend_schema,
|
||||
extend_schema_view,
|
||||
OpenApiParameter,
|
||||
OpenApiExample,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
from rest_framework.pagination import LimitOffsetPagination
|
||||
|
||||
from .models import ProductModel, ProductChatModel
|
||||
from utils.pagination import StructurePagination
|
||||
import openai
|
||||
from django.conf import settings
|
||||
|
||||
ASSISTANT_ID = 'asst_1wOnCKncEHkOfp0FjOIz4Xkp'
|
||||
|
||||
|
||||
# Serializer for the `new_message` field in POST requests
|
||||
class NewMessageSerializer(serializers.Serializer):
|
||||
new_message = serializers.CharField(
|
||||
required=True,
|
||||
help_text="The message content to send to the chat."
|
||||
)
|
||||
|
||||
|
||||
# Custom Pagination Class
|
||||
class StructurePagination(LimitOffsetPagination):
|
||||
default_limit = 10
|
||||
max_limit = 100
|
||||
|
||||
|
||||
# Documentation for the ProductChatView
|
||||
@extend_schema_view(
|
||||
get=extend_schema(
|
||||
summary="Retrieve messages for a product chat",
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="limit",
|
||||
description="Number of results to return per page.",
|
||||
required=False,
|
||||
type=int,
|
||||
default=10,
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="offset",
|
||||
description="The starting position of the results.",
|
||||
required=False,
|
||||
type=int,
|
||||
default=0,
|
||||
),
|
||||
],
|
||||
responses={
|
||||
200: OpenApiExample(
|
||||
"Chat messages retrieved",
|
||||
value={
|
||||
"messages": [
|
||||
{"sender": "user", "content": "Hello!"},
|
||||
{"sender": "assistant", "content": "How can I help you?"}
|
||||
]
|
||||
}
|
||||
),
|
||||
},
|
||||
),
|
||||
post=extend_schema(
|
||||
summary="Send a new message in the product chat",
|
||||
request=NewMessageSerializer,
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="limit",
|
||||
description="Number of results to return per page.",
|
||||
required=False,
|
||||
type=int,
|
||||
default=10,
|
||||
),
|
||||
OpenApiParameter(
|
||||
name="offset",
|
||||
description="The starting position of the results.",
|
||||
required=False,
|
||||
type=int,
|
||||
default=0,
|
||||
),
|
||||
],
|
||||
responses={
|
||||
200: OpenApiExample(
|
||||
"Message sent successfully",
|
||||
value={
|
||||
"messages": [
|
||||
{"sender": "user", "content": "Hello!"},
|
||||
{"sender": "assistant", "content": "How can I help you?"}
|
||||
]
|
||||
}
|
||||
),
|
||||
400: OpenApiExample(
|
||||
"Error example",
|
||||
value={"detail": "پیام جدید نمیتواند خالی باشد"},
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
class ProductChatView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
pagination_class = StructurePagination
|
||||
|
||||
def get(self, request, pk):
|
||||
"""
|
||||
Retrieve all messages for a product chat.
|
||||
"""
|
||||
user = request.user
|
||||
product = get_object_or_404(ProductModel, id=pk)
|
||||
chat, created = ProductChatModel.objects.get_or_create(user=user, product=product)
|
||||
|
||||
client = openai.OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||
message_response = client.beta.threads.messages.list(thread_id=chat.thread)
|
||||
|
||||
# Format messages
|
||||
formatted_messages = []
|
||||
for message in message_response.data:
|
||||
for content in message.content:
|
||||
if content.type == "text" and 'this is the start of the chat greet the user this chat is about the product with given detail:' not in content.text.value:
|
||||
sender = 'user' if message.role == 'user' else 'ai'
|
||||
formatted_messages.append({'sender': sender, 'content': content.text.value})
|
||||
|
||||
# Paginate results
|
||||
paginator = StructurePagination()
|
||||
paginated_messages = paginator.paginate_queryset(formatted_messages, request)
|
||||
return paginator.get_paginated_response(paginated_messages)
|
||||
|
||||
def post(self, request, pk):
|
||||
"""
|
||||
Send a new message in the product chat.
|
||||
"""
|
||||
user = request.user
|
||||
product = get_object_or_404(ProductModel, id=pk)
|
||||
chat, created = ProductChatModel.objects.get_or_create(user=user, product=product)
|
||||
|
||||
if created:
|
||||
return Response({'detail': 'چت این کاربر با این محصول هنوز ساخته نشده'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
new_message = request.data.get('new_message', '').strip()
|
||||
if not new_message:
|
||||
return Response({'detail': 'پیام جدید نمیتواند خالی باشد'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
client = openai.OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||
|
||||
# Send the user message
|
||||
client.beta.threads.messages.create(
|
||||
thread_id=chat.thread,
|
||||
role="user",
|
||||
content=new_message
|
||||
)
|
||||
|
||||
# Start the assistant's run
|
||||
run = client.beta.threads.runs.create(thread_id=chat.thread, assistant_id=ASSISTANT_ID)
|
||||
while run.status != "completed":
|
||||
run = client.beta.threads.runs.retrieve(thread_id=chat.thread, run_id=run.id)
|
||||
sleep(1)
|
||||
|
||||
# Fetch the updated messages
|
||||
message_response = client.beta.threads.messages.list(thread_id=chat.thread)
|
||||
formatted_messages = []
|
||||
for message in message_response.data:
|
||||
for content in message.content:
|
||||
if content.type == "text":
|
||||
sender = 'user' if message.role == 'user' else 'ai'
|
||||
formatted_messages.append({'sender': sender, 'content': content.text.value})
|
||||
|
||||
paginator = StructurePagination()
|
||||
paginated_messages = paginator.paginate_queryset(formatted_messages, request)
|
||||
return paginator.get_paginated_response(paginated_messages)
|
||||
Reference in New Issue
Block a user