Skip to content
This repository has been archived by the owner on Jan 5, 2025. It is now read-only.

Commit

Permalink
Merge pull request #233 from lvalics/main
Browse files Browse the repository at this point in the history
Started to add swagger-ui docs
  • Loading branch information
codebanesr authored Feb 5, 2024
2 parents ff9edf8 + 33aa163 commit 8e906d7
Show file tree
Hide file tree
Showing 50 changed files with 2,883 additions and 1,176 deletions.
23 changes: 23 additions & 0 deletions dj_backend_server/api/chatbot_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.http import JsonResponse
from web.models.chatbot import Chatbot
from drf_spectacular.utils import extend_schema, OpenApiParameter
from drf_spectacular.types import OpenApiTypes
from rest_framework.decorators import api_view, parser_classes
from rest_framework.parsers import MultiPartParser, FormParser


@extend_schema(
methods=['GET'],
description="Get Chatbot info based on Bot ID",
request=None,
)
@api_view(['GET'])
def get_chatbot_info(request, bot_id):
'''
Easy way to get chatbot info based on Bot ID
'''
try:
bot = Chatbot.objects.get(id=bot_id)
return JsonResponse({'id': bot.id, 'name': bot.name}, status=200)
except Chatbot.DoesNotExist:
return JsonResponse({'error': 'Chatbot not found'}, status=404)
57 changes: 52 additions & 5 deletions dj_backend_server/api/pdf_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,62 @@
associates the uploaded PDFs with a chatbot based on the provided bot token, and triggers further
processing of the PDFs. The endpoint requires a POST request with the PDF files and optional flags.
"""

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from web.services.handle_pdf_datasource import HandlePdfDataSource
from web.models.chatbot import Chatbot
from web.signals.pdf_datasource_was_added import pdf_data_source_added
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiExample
from drf_spectacular.types import OpenApiTypes
from rest_framework.decorators import api_view, parser_classes
from rest_framework.parsers import MultiPartParser, FormParser


@csrf_exempt
@require_POST
@extend_schema(
methods=['POST'],
description="Upload PDF files and associate them with a chatbot based on the provided bot token.",
request={
'multipart/form-data': {
'type': 'object',
'properties': {
'pdffiles': {
'type': 'array',
'items': {
'type': 'string',
'format': 'binary'
},
'description': 'The PDF file(s) to be uploaded. Can be a single file or multiple files.',
},
'delete_folder_flag': {
'type': 'integer',
'description': 'Flag indicating whether to delete the folder after processing (0 or 1)',
},
'ocr_pdf_file': {
'type': 'integer',
'description': 'Flag indicating that the file needs to be sent to OCR API (0 or 1)',
}
}
}
},
responses={200: OpenApiTypes.OBJECT},
parameters=[
OpenApiParameter(name='X-Bot-Token', description="Token to authenticate the chatbot", required=True, type=OpenApiTypes.STR, location=OpenApiParameter.HEADER),
],
examples=[
OpenApiExample(
name='Example upload',
description='An example of a PDF file upload',
request_only=True,
value={
'pdffiles': 'file content here',
'delete_folder_flag': 1,
'ocr_pdf_file': 1,
}
),
],
)
@api_view(['POST'])
@parser_classes((MultiPartParser, FormParser))
def upload_pdf_api(request):
"""
API endpoint for uploading PDF files. It expects a POST request with the following parameters:
Expand Down Expand Up @@ -41,4 +87,5 @@ def upload_pdf_api(request):
# Trigger the PdfDataSourceWasAdded event
pdf_data_source_added.send(sender='create_via_pdf_flow', bot_id=bot.id, data_source_id=data_source.id, delete_folder_flag=delete_folder_flag, ocr_pdf_file=ocr_pdf_file, text_data=text_data)
return JsonResponse({'message': 'PDF uploaded and chatbot created successfully', 'data_source_id': data_source.id, 'bot_id': bot.id})



16 changes: 14 additions & 2 deletions dj_backend_server/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
from django.urls import path
from .views import views_message, views_auth, views_ingest, views_chat
from .chatbot_info import get_chatbot_info
from .pdf_handler import upload_pdf_api
from .views.views_message import handle_feedback
from django.contrib.auth.decorators import login_required
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView


urlpatterns = [
path('send_search_request/', views_message.send_search_request, name='send_search_request'),
path('chat/search/', views_message.send_search_request, name='send_search_request'),
path('chat/init/', views_message.init_chat, name='init_chat'),
path('chat/send/', views_message.send_chat, name='send_chat'),
path('rate/', handle_feedback, name='handle_feedback'),
# website/codebase/pdf ingestion endpoint
path('ingest/', views_ingest.ingest, name='ingest'),
path('chat/', views_chat.chat, name='chat'),
Expand All @@ -15,4 +21,10 @@
path('reset-password/', views_auth.reset_password, name='reset-password'),
# PDF upload API endpoint
path('upload_pdf/', upload_pdf_api, name='upload_pdf'),
]
path('chatbot/<str:bot_id>/', get_chatbot_info, name='get_chatbot_info'),
# SCHEMA
path('schema/', login_required(SpectacularAPIView.as_view()), name='schema'),
path('schema/swagger-ui/', login_required(SpectacularSwaggerView.as_view(url_name='schema')), name='swagger-ui'),
path('schema/redoc/', login_required(SpectacularRedocView.as_view(url_name='schema')), name='redoc'),

]
13 changes: 3 additions & 10 deletions dj_backend_server/api/views/views_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,6 @@ def chat(request):
sanitized_question = question.strip().replace('\n', ' ')

vector_store = get_vector_store(StoreOptions(namespace=namespace))
# Serialize vector_store information to JSON format for logging
# vector_store_info = {
# "type": str(type(vector_store)),
# "namespace": namespace
# }
# print (f"Vector_store_info: {json.dumps(vector_store_info)}")
# print (f"mode: {mode} + initial_prompt: {initial_prompt} + sanitized_question: {sanitized_question} + session_id: {session_id}")

response_text = get_completion_response(vector_store=vector_store, initial_prompt=initial_prompt,mode=mode, sanitized_question=sanitized_question, session_id=session_id)

Expand All @@ -82,7 +75,8 @@ def chat(request):
session_id=session_id,
)
])
return JsonResponse({'text': response_text['text']})

return JsonResponse({'text': response_text})

elif isinstance(response_text, str):
ChatHistory.objects.bulk_create([
Expand All @@ -101,11 +95,10 @@ def chat(request):
session_id=session_id,
)
])
# print(f"ChatHistory created with response: {response_text}")

return JsonResponse({'text': response_text})

else:
# print(f"Response does not contain 'text' key: {response_text}")
return JsonResponse({'error': 'Unexpected response from API'}, status=500)

except json.JSONDecodeError:
Expand Down
74 changes: 53 additions & 21 deletions dj_backend_server/api/views/views_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import json
import os
from django.http import JsonResponse
from django.utils.html import escape
from django.shortcuts import get_object_or_404
from django.conf import settings
from django.views.decorators.http import require_POST, require_GET
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from web.models.chatbot import Chatbot
from web.utils.common import get_session_id
from web.models.chat_histories import ChatHistory

from django.template.loader import render_to_string

class ChatbotResponse:
"""
Expand Down Expand Up @@ -73,7 +75,7 @@ def init_chat(request):
})


@csrf_exempt
@csrf_exempt
@require_POST
def send_search_request(request):
"""
Expand All @@ -92,9 +94,9 @@ def send_search_request(request):
"""
try:
# Validate the request data
message = request.POST.get('message')
history = request.POST.getlist('history[]')

data = json.loads(request.body)
message = data.get('message')
history = data.get('history', [])
# Implement the equivalent logic for validation
if not message:
return JsonResponse({
Expand All @@ -104,17 +106,21 @@ def send_search_request(request):

bot_token = request.headers.get('X-Bot-Token')
bot = get_object_or_404(Chatbot, token=bot_token)

session_id = get_session_id(request=request, bot_id=bot.id)
history = ChatHistory.objects.filter(session_id=session_id)
history_entries = [{"message": entry.message, "from_user": entry.from_user} for entry in history]

# Implement the equivalent logic to send the HTTP request to the external API
# print(os.getenv('APP_URL'))
response = requests.post(
os.getenv('APP_URL') + '/api/chat/',
json={
'question': message,
'namespace': str(bot.id), # Assuming getId returns a UUID object
'namespace': str(bot.id),
'mode': "assistant",
'initial_prompt': bot.prompt_message,
'history': history # Assuming the API expects the chat history
'history': history_entries,
'token': bot_token,
"session_id": session_id
},
timeout=200
)
Expand Down Expand Up @@ -164,7 +170,7 @@ def send_chat(request):
content = data.get('content')
history = data.get('history')
# content_type = data.get('type')

session_id = get_session_id(request=request, bot_id=bot.id)
history = ChatHistory.objects.filter(session_id=session_id)
history_entries = [{"message": entry.message, "from_user": entry.from_user} for entry in history]
Expand All @@ -179,7 +185,7 @@ def send_chat(request):
}, status=400)

# Implement the equivalent logic to send the HTTP request to the external API
# print(os.getenv('APP_URL'))

response = requests.post(
os.getenv('APP_URL') + '/api/chat/',
json={
Expand All @@ -193,7 +199,6 @@ def send_chat(request):
},
timeout=200
)
# print(f"Response in JSON {response.json()}")

"""
This block will first check if the response content is not empty. If it is empty,
Expand All @@ -219,14 +224,18 @@ def send_chat(request):
})

bot_response = ChatbotResponse(response.json())

# context = {'APP_URL': settings.APP_URL, session_id: session_id}
feedback_form_html = render_to_string('widgets/feedback.html', {'APP_URL': settings.APP_URL, 'session_id': session_id})
print(f"Response in JSON {session_id}")
return JsonResponse({
"type": "text",
"response": {
"text": bot_response.get_bot_reply()
}
})

"type": "text",
"response": {
"text": bot_response.get_bot_reply(),
"html": feedback_form_html,
"session_id": session_id
}
})

except Exception as e:
# @TODO: Log the exception into database.
import traceback
Expand All @@ -237,4 +246,27 @@ def send_chat(request):
"response": {
"text": "I'm unable to help you at the moment, please try again later. **code: b404**"
}
}, status=500)
}, status=500)


@csrf_exempt
@require_POST
def handle_feedback(request):
try:
data = json.loads(request.body)
# Assuming the session_id is stored in the user's session or a secure cookie
session_id = data.get('session_id')
helpful = data.get('helpful', None) # This can be True, False, or None

# Assuming you have a session_id field in your ChatHistory model
# and a new field for storing feedback
# Update the latest message for the given session_id with the helpful value
chat_history = ChatHistory.objects.filter(session_id=session_id).order_by('-updated_at').first()
if chat_history:
chat_history.feedback = helpful
chat_history.save()
return JsonResponse({'status': 'success'}, status=200)
else:
return JsonResponse({'error': 'Chat history not found'}, status=404)
except Exception as e:
return JsonResponse({'error': 'An error occurred'}, status=500)
Loading

0 comments on commit 8e906d7

Please sign in to comment.