update
This commit is contained in:
parent
2b74f92ab6
commit
152518ebdc
Binary file not shown.
Binary file not shown.
@ -61,6 +61,7 @@ INSTALLED_APPS = [
|
|||||||
'django_ledger',
|
'django_ledger',
|
||||||
'djmoney',
|
'djmoney',
|
||||||
'sslserver',
|
'sslserver',
|
||||||
|
'haikalbot',
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ urlpatterns = [
|
|||||||
path('api/', include('api.urls')),
|
path('api/', include('api.urls')),
|
||||||
path('dj-rest-auth/', include('dj_rest_auth.urls')),
|
path('dj-rest-auth/', include('dj_rest_auth.urls')),
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
urlpatterns += i18n_patterns(
|
urlpatterns += i18n_patterns(
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
@ -21,7 +22,7 @@ urlpatterns += i18n_patterns(
|
|||||||
path('prometheus/', include('django_prometheus.urls')),
|
path('prometheus/', include('django_prometheus.urls')),
|
||||||
path('', include('inventory.urls')),
|
path('', include('inventory.urls')),
|
||||||
path('ledger/', include('django_ledger.urls', namespace='django_ledger')),
|
path('ledger/', include('django_ledger.urls', namespace='django_ledger')),
|
||||||
|
path("haikalbot/", include("haikalbot.urls")),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|||||||
0
haikalbot/__init__.py
Normal file
0
haikalbot/__init__.py
Normal file
3
haikalbot/admin.py
Normal file
3
haikalbot/admin.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
haikalbot/apps.py
Normal file
6
haikalbot/apps.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class HaikalbotConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'haikalbot'
|
||||||
83
haikalbot/chatbot_logic.py
Normal file
83
haikalbot/chatbot_logic.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import re
|
||||||
|
from nltk.tokenize import word_tokenize
|
||||||
|
from django.db.models import Q
|
||||||
|
from inventory.models import Car # Import your car-related models
|
||||||
|
import nltk
|
||||||
|
# Download required NLTK resources
|
||||||
|
try:
|
||||||
|
|
||||||
|
nltk.download("punkt")
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("Ensure nltk is installed by running 'pip install nltk'.")
|
||||||
|
|
||||||
|
# Static responses for predefined intents
|
||||||
|
RESPONSES = {
|
||||||
|
"greet": ["Hello! How can I assist you today with Haikal Car Inventory?"],
|
||||||
|
"inventory_check": ["You can check the car inventory in the Cars section. Do you want to search for a specific car?"],
|
||||||
|
"car_status": ["If a car is sold, it will either be marked as SOLD or removed from the inventory, as per your preferences."],
|
||||||
|
"sell_process": ["To sell a car, the process involves creating a Sell Order, adding the customer, confirming payment, generating an invoice, and finally delivering the car."],
|
||||||
|
"transfer_process": ["Dealers can transfer cars to other branches or dealers for display or sale. This is handled through Sell Orders as well."],
|
||||||
|
"bye": ["Goodbye! If you need further assistance, just ask!"],
|
||||||
|
}
|
||||||
|
|
||||||
|
def clean_input(user_input):
|
||||||
|
"""
|
||||||
|
Clean and tokenize user input.
|
||||||
|
"""
|
||||||
|
user_input = user_input.lower()
|
||||||
|
user_input = re.sub(r"[^\w\s]", "", user_input) # Remove punctuation
|
||||||
|
return word_tokenize(user_input)
|
||||||
|
|
||||||
|
def classify_input(tokens):
|
||||||
|
"""
|
||||||
|
Classify user intent based on tokens.
|
||||||
|
"""
|
||||||
|
if any(word in tokens for word in ["hello", "hi", "hey"]):
|
||||||
|
return "greet"
|
||||||
|
elif any(word in tokens for word in ["inventory", "cars", "check"]):
|
||||||
|
return "inventory_check"
|
||||||
|
elif any(word in tokens for word in ["sell", "sold", "process"]):
|
||||||
|
return "sell_process"
|
||||||
|
elif any(word in tokens for word in ["transfer", "branch", "display"]):
|
||||||
|
return "transfer_process"
|
||||||
|
elif any(word in tokens for word in ["bye", "goodbye", "exit"]):
|
||||||
|
return "bye"
|
||||||
|
elif any(word in tokens for word in ["price", "cost", "value"]):
|
||||||
|
return "car_price"
|
||||||
|
else:
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
def get_dynamic_response(intent, tokens):
|
||||||
|
"""
|
||||||
|
Generate dynamic responses by querying the database.
|
||||||
|
"""
|
||||||
|
if intent == "car_price":
|
||||||
|
# Extract car name from tokens
|
||||||
|
car_name = " ".join([word.capitalize() for word in tokens])
|
||||||
|
try:
|
||||||
|
car = Car.objects.filter(Q(make__icontains=car_name) | Q(model__icontains=car_name)).first()
|
||||||
|
if car:
|
||||||
|
return f"The price of {car_name} is {car.finance.selling_price}."
|
||||||
|
return f"Sorry, no car matching '{car_name}' was found in the inventory."
|
||||||
|
except Exception as e:
|
||||||
|
return f"An error occurred while retrieving the car price: {str(e)}"
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_response(user_input):
|
||||||
|
"""
|
||||||
|
Generate a response based on the user's input.
|
||||||
|
"""
|
||||||
|
tokens = clean_input(user_input)
|
||||||
|
intent = classify_input(tokens)
|
||||||
|
|
||||||
|
# Check for a dynamic response
|
||||||
|
dynamic_response = get_dynamic_response(intent, tokens)
|
||||||
|
if dynamic_response:
|
||||||
|
return dynamic_response
|
||||||
|
|
||||||
|
# Return a static response if available
|
||||||
|
if intent in RESPONSES:
|
||||||
|
return RESPONSES[intent][0]
|
||||||
|
|
||||||
|
# Default response for unknown intents
|
||||||
|
return "I'm sorry, I didn't understand that. Could you rephrase your question about the Haikal system?"
|
||||||
26
haikalbot/migrations/0001_initial.py
Normal file
26
haikalbot/migrations/0001_initial.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-18 16:49
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0030_alter_carfinance_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ChatLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('user_message', models.TextField()),
|
||||||
|
('chatbot_response', models.TextField()),
|
||||||
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('dealer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='chatlogs', to='inventory.dealer')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
0
haikalbot/migrations/__init__.py
Normal file
0
haikalbot/migrations/__init__.py
Normal file
12
haikalbot/models.py
Normal file
12
haikalbot/models.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from django.db import models
|
||||||
|
from inventory.models import Dealer
|
||||||
|
|
||||||
|
|
||||||
|
class ChatLog(models.Model):
|
||||||
|
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name='chatlogs')
|
||||||
|
user_message = models.TextField()
|
||||||
|
chatbot_response = models.TextField()
|
||||||
|
timestamp = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.user_message
|
||||||
3
haikalbot/tests.py
Normal file
3
haikalbot/tests.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
7
haikalbot/urls.py
Normal file
7
haikalbot/urls.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("", views.ChatbotView.as_view(), name="chatbot"),
|
||||||
|
]
|
||||||
35
haikalbot/views.py
Normal file
35
haikalbot/views.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from django.views import View
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.http import JsonResponse
|
||||||
|
from .chatbot_logic import get_response
|
||||||
|
import json
|
||||||
|
|
||||||
|
class ChatbotView(View):
|
||||||
|
"""
|
||||||
|
Class-based view to handle chatbot template rendering (GET)
|
||||||
|
and GPT-4-based chatbot API responses (POST).
|
||||||
|
"""
|
||||||
|
def get(self, request):
|
||||||
|
"""
|
||||||
|
Render the chatbot interface template.
|
||||||
|
"""
|
||||||
|
return render(request, "haikalbot/chatbot.html")
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
"""
|
||||||
|
Handle chatbot API requests and return responses as JSON.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Parse JSON payload from the request body
|
||||||
|
data = json.loads(request.body)
|
||||||
|
user_message = data.get("message", "").strip()
|
||||||
|
|
||||||
|
if not user_message:
|
||||||
|
return JsonResponse({"error": "Message cannot be empty."}, status=400)
|
||||||
|
|
||||||
|
# Get GPT-4 response
|
||||||
|
chatbot_response = get_response(user_message)
|
||||||
|
|
||||||
|
return JsonResponse({"response": chatbot_response}, status=200)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return JsonResponse({"error": "Invalid JSON format."}, status=400)
|
||||||
Binary file not shown.
@ -962,5 +962,3 @@ class RepresentativeDeleteView(LoginRequiredMixin, DeleteView):
|
|||||||
template_name = 'representatives/representative_confirm_delete.html'
|
template_name = 'representatives/representative_confirm_delete.html'
|
||||||
success_url = reverse_lazy('representative_list')
|
success_url = reverse_lazy('representative_list')
|
||||||
success_message = "Representative deleted successfully."
|
success_message = "Representative deleted successfully."
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,30 @@
|
|||||||
alabaster==1.0.0
|
alabaster==1.0.0
|
||||||
annotated-types==0.7.0
|
annotated-types==0.7.0
|
||||||
anyio==4.6.2.post1
|
anyio==4.7.0
|
||||||
|
arabic-reshaper==3.0.0
|
||||||
asgiref==3.8.1
|
asgiref==3.8.1
|
||||||
astroid==3.3.5
|
astroid==3.3.6
|
||||||
attrs==23.2.0
|
attrs==23.2.0
|
||||||
autopep8==2.3.1
|
autopep8==2.3.1
|
||||||
babel==2.16.0
|
babel==2.16.0
|
||||||
certifi==2024.8.30
|
beautifulsoup4==4.12.3
|
||||||
|
bleach==6.2.0
|
||||||
|
blinker==1.9.0
|
||||||
|
certifi==2024.12.14
|
||||||
cffi==1.17.1
|
cffi==1.17.1
|
||||||
chardet==5.2.0
|
chardet==5.2.0
|
||||||
charset-normalizer==3.4.0
|
charset-normalizer==3.4.0
|
||||||
|
click==8.1.7
|
||||||
|
colorama==0.4.6
|
||||||
|
commonmark==0.9.1
|
||||||
crispy-bootstrap5==2024.10
|
crispy-bootstrap5==2024.10
|
||||||
cryptography==44.0.0
|
cryptography==44.0.0
|
||||||
|
desert==2020.11.18
|
||||||
dill==0.3.9
|
dill==0.3.9
|
||||||
distro==1.9.0
|
distro==1.9.0
|
||||||
dj-rest-auth==7.0.0
|
dj-rest-auth==7.0.0
|
||||||
dj-shop-cart==7.1.1
|
dj-shop-cart==7.1.1
|
||||||
Django
|
Django==5.1.4
|
||||||
django-allauth==65.3.0
|
django-allauth==65.3.0
|
||||||
django-autoslug==1.9.9
|
django-autoslug==1.9.9
|
||||||
django-bootstrap5==24.3
|
django-bootstrap5==24.3
|
||||||
@ -29,83 +37,133 @@ django-filter==24.3
|
|||||||
django-formtools==2.5.1
|
django-formtools==2.5.1
|
||||||
django-ledger==0.7.0
|
django-ledger==0.7.0
|
||||||
django-money==3.5.3
|
django-money==3.5.3
|
||||||
|
django-nine==0.2.7
|
||||||
|
django-nonefield==0.4
|
||||||
django-phonenumber-field==8.0.0
|
django-phonenumber-field==8.0.0
|
||||||
django-prometheus==2.3.1
|
django-prometheus==2.3.1
|
||||||
django-sekizai==4.1.0
|
django-sekizai==4.1.0
|
||||||
django-silk==5.3.1
|
django-silk==5.3.2
|
||||||
django-sslserver==0.22
|
django-sslserver==0.22
|
||||||
django-tables2==2.7.0
|
django-tables2==2.7.0
|
||||||
django-treebeard==4.7.1
|
django-treebeard==4.7.1
|
||||||
django-view-breadcrumbs==2.5.1
|
django-view-breadcrumbs==2.5.1
|
||||||
djangocms-admin-style==3.3.1
|
djangocms-admin-style==3.3.1
|
||||||
djangorestframework==3.15.2
|
djangorestframework==3.15.2
|
||||||
djangorestframework-simplejwt==5.3.1
|
|
||||||
djangoviz==0.1.1
|
djangoviz==0.1.1
|
||||||
docutils==0.21.2
|
docutils==0.21.2
|
||||||
|
easy-thumbnails==2.10
|
||||||
et_xmlfile==2.0.0
|
et_xmlfile==2.0.0
|
||||||
Faker==33.1.0
|
Faker==33.1.0
|
||||||
|
Flask==3.1.0
|
||||||
gprof2dot==2024.6.6
|
gprof2dot==2024.6.6
|
||||||
graphqlclient==0.2.4
|
graphqlclient==0.2.4
|
||||||
h11==0.14.0
|
h11==0.14.0
|
||||||
httpcore==1.0.7
|
httpcore==1.0.7
|
||||||
httpx==0.28.0
|
httpx==0.28.1
|
||||||
idna==3.10
|
idna==3.10
|
||||||
imagesize==1.4.1
|
imagesize==1.4.1
|
||||||
iso4217==1.12.20240625
|
iso4217==1.12.20240625
|
||||||
isodate==0.7.2
|
isodate==0.7.2
|
||||||
isort==5.13.2
|
isort==5.13.2
|
||||||
|
itsdangerous==2.2.0
|
||||||
Jinja2==3.1.4
|
Jinja2==3.1.4
|
||||||
jiter==0.8.0
|
jiter==0.8.2
|
||||||
|
joblib==1.4.2
|
||||||
ledger==1.0.1
|
ledger==1.0.1
|
||||||
lxml==5.3.0
|
lxml==5.3.0
|
||||||
Markdown==3.7
|
Markdown==3.7
|
||||||
MarkupSafe==3.0.2
|
MarkupSafe==3.0.2
|
||||||
|
marshmallow==3.23.2
|
||||||
mccabe==0.7.0
|
mccabe==0.7.0
|
||||||
newrelic==10.3.1
|
MouseInfo==0.1.3
|
||||||
|
mypy-extensions==1.0.0
|
||||||
|
newrelic==10.4.0
|
||||||
|
nltk==3.9.1
|
||||||
|
numpy==2.2.0
|
||||||
oauthlib==3.2.2
|
oauthlib==3.2.2
|
||||||
ofxtools==0.9.5
|
ofxtools==0.9.5
|
||||||
openai==1.56.2
|
openai==1.58.1
|
||||||
openpyxl==3.1.5
|
openpyxl==3.1.5
|
||||||
|
outcome==1.3.0.post0
|
||||||
packaging==24.2
|
packaging==24.2
|
||||||
|
pandas==2.2.3
|
||||||
pdfkit==1.0.0
|
pdfkit==1.0.0
|
||||||
phonenumbers==8.13.51
|
phonenumbers==8.13.52
|
||||||
pillow==11.0.0
|
pillow==11.0.0
|
||||||
platformdirs==4.3.6
|
platformdirs==4.3.6
|
||||||
prometheus_client==0.21.1
|
prometheus_client==0.21.1
|
||||||
psycopg==3.2.3
|
psycopg==3.2.3
|
||||||
psycopg-binary==3.2.3
|
psycopg-binary==3.2.3
|
||||||
|
psycopg-c==3.2.3
|
||||||
py-moneyed==3.0
|
py-moneyed==3.0
|
||||||
|
PyAutoGUI==0.9.54
|
||||||
pycodestyle==2.12.1
|
pycodestyle==2.12.1
|
||||||
pycparser==2.22
|
pycparser==2.22
|
||||||
pydantic==2.10.3
|
pydantic==2.10.4
|
||||||
pydantic_core==2.27.1
|
pydantic_core==2.27.2
|
||||||
pydotplus==2.0.2
|
pydotplus==2.0.2
|
||||||
|
PyGetWindow==0.0.9
|
||||||
Pygments==2.18.0
|
Pygments==2.18.0
|
||||||
PyJWT==2.10.1
|
PyJWT==2.10.1
|
||||||
pylint==3.3.2
|
pylint==3.3.2
|
||||||
|
PyMsgBox==1.0.9
|
||||||
PyMySQL==1.1.1
|
PyMySQL==1.1.1
|
||||||
|
pyobjc-core==10.3.2
|
||||||
|
pyobjc-framework-Cocoa==10.3.2
|
||||||
|
pyobjc-framework-Quartz==10.3.2
|
||||||
pyparsing==3.2.0
|
pyparsing==3.2.0
|
||||||
|
pyperclip==1.9.0
|
||||||
pypng==0.20220715.0
|
pypng==0.20220715.0
|
||||||
|
PyRect==0.2.0
|
||||||
|
PyScreeze==1.0.1
|
||||||
pyserial==3.5
|
pyserial==3.5
|
||||||
|
PySocks==1.7.1
|
||||||
|
python-bidi==0.6.3
|
||||||
python-dateutil==2.9.0.post0
|
python-dateutil==2.9.0.post0
|
||||||
python-openid==2.2.5
|
python-openid==2.2.5
|
||||||
python3-saml==1.16.0
|
python3-saml==1.16.0
|
||||||
|
pytweening==1.2.0
|
||||||
pytz==2024.2
|
pytz==2024.2
|
||||||
pyvin==0.0.2
|
pyvin==0.0.2
|
||||||
|
pywa==2.4.0
|
||||||
|
pywhat==5.1.0
|
||||||
|
pywhatkit==5.4
|
||||||
qrcode==8.0
|
qrcode==8.0
|
||||||
|
regex==2024.11.6
|
||||||
reportlab==4.2.5
|
reportlab==4.2.5
|
||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
requests-oauthlib==2.0.0
|
requests-oauthlib==2.0.0
|
||||||
six==1.16.0
|
rich==10.16.2
|
||||||
|
rubicon-objc==0.4.9
|
||||||
|
scikit-learn==1.6.0
|
||||||
|
scipy==1.14.1
|
||||||
|
selenium==4.27.1
|
||||||
|
six==1.17.0
|
||||||
sniffio==1.3.1
|
sniffio==1.3.1
|
||||||
snowballstemmer==2.2.0
|
snowballstemmer==2.2.0
|
||||||
sqlparse==0.5.2
|
sortedcontainers==2.4.0
|
||||||
|
soupsieve==2.6
|
||||||
|
SQLAlchemy==2.0.36
|
||||||
|
sqlparse==0.5.3
|
||||||
tablib==3.7.0
|
tablib==3.7.0
|
||||||
|
threadpoolctl==3.5.0
|
||||||
tomlkit==0.13.2
|
tomlkit==0.13.2
|
||||||
tqdm==4.67.1
|
tqdm==4.67.1
|
||||||
|
trio==0.27.0
|
||||||
|
trio-websocket==0.11.1
|
||||||
|
typing-inspect==0.9.0
|
||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
|
tzdata==2024.2
|
||||||
|
Unidecode==1.3.8
|
||||||
upgrade-requirements==1.7.0
|
upgrade-requirements==1.7.0
|
||||||
urllib3==2.2.3
|
urllib3==2.2.3
|
||||||
vin==0.6.2
|
vin==0.6.2
|
||||||
vininfo==1.8.0
|
vininfo==1.8.0
|
||||||
|
vishap==0.1.5
|
||||||
|
vpic-api==0.7.4
|
||||||
|
webencodings==0.5.1
|
||||||
|
websocket-client==1.8.0
|
||||||
|
Werkzeug==3.1.3
|
||||||
|
wikipedia==1.4.0
|
||||||
|
wsproto==1.2.0
|
||||||
xmlsec==1.3.14
|
xmlsec==1.3.14
|
||||||
|
|||||||
90
templates/haikalbot/chatbot.html
Normal file
90
templates/haikalbot/chatbot.html
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n static %}
|
||||||
|
|
||||||
|
{% block title %}{{ _("HaikalBot") }}{% endblock title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<style>
|
||||||
|
|
||||||
|
#chatbox {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
height: 200px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container p-2">
|
||||||
|
<div class="card shadow-sm rounded shadow">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h4 class="mb-0">{% trans 'HaikalBot' %}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<div id="chatbox">
|
||||||
|
<p><b>{% trans 'HaikalBot' %}:</b> {% trans 'Hello! How can I assist you today?' %}</p>
|
||||||
|
</div>
|
||||||
|
<label for="userMessage"></label>
|
||||||
|
<input class="form-control form-control-sm"
|
||||||
|
type="text" id="userMessage"
|
||||||
|
placeholder="{% trans 'Type your message here...' %}" />
|
||||||
|
<button class="btn btn-sm btn-success m-2" onclick="sendMessage()">{% trans 'Send' %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Script to send to api -->
|
||||||
|
<script>
|
||||||
|
function getCookie(name) {
|
||||||
|
let cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie !== '') {
|
||||||
|
const cookies = document.cookie.split(';');
|
||||||
|
for (let cookie of cookies) {
|
||||||
|
cookie = cookie.trim();
|
||||||
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const csrfToken = getCookie('csrftoken');
|
||||||
|
|
||||||
|
|
||||||
|
async function sendMessage() {
|
||||||
|
const userMessage = document.getElementById("userMessage").value;
|
||||||
|
|
||||||
|
if (!userMessage.trim()) {
|
||||||
|
alert("Please enter a message.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch("", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-CSRFToken": csrfToken,
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ message: userMessage }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const data = await response.json();
|
||||||
|
const chatbox = document.getElementById("chatbox");
|
||||||
|
chatbox.innerHTML += `<p><b>{% trans 'You' %}:</b> ${userMessage}</p>`;
|
||||||
|
chatbox.innerHTML += `<p><b>{% trans 'HaikalBot' %}:</b> ${data.response}</p>`;
|
||||||
|
document.getElementById("userMessage").value = "";
|
||||||
|
chatbox.scrollTop = chatbox.scrollHeight;
|
||||||
|
} else {
|
||||||
|
alert("An error occurred.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
67
whatsapp_bot.py
Normal file
67
whatsapp_bot.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import re
|
||||||
|
import arabic_reshaper
|
||||||
|
from bidi.algorithm import get_display
|
||||||
|
from pywa import WhatsApp
|
||||||
|
|
||||||
|
# Initialize the WhatsApp bot
|
||||||
|
bot = WhatsApp(
|
||||||
|
phone_id="00966535521547",
|
||||||
|
token="c446eba6-fcfe-437c-923a-a554c25578dd"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pre-defined responses in English and Arabic
|
||||||
|
responses = {
|
||||||
|
"greet": {
|
||||||
|
"en": "Hello! How can I assist you with Haikal Car Inventory?",
|
||||||
|
"ar": get_display(arabic_reshaper.reshape("مرحباً! كيف يمكنني مساعدتك في نظام هيكل لإدارة السيارات؟"))
|
||||||
|
},
|
||||||
|
"sell_process": {
|
||||||
|
"en": "To sell a car: Create a Sell Order, add a customer, confirm payment, generate an invoice, and deliver the car.",
|
||||||
|
"ar": get_display(arabic_reshaper.reshape("لبيع السيارة: قم بإنشاء طلب بيع، إضافة العميل، تأكيد الدفع، إنشاء الفاتورة، وتسليم السيارة."))
|
||||||
|
},
|
||||||
|
"inventory_check": {
|
||||||
|
"en": "You can check available cars in the inventory. Do you want details on any specific car?",
|
||||||
|
"ar": get_display(arabic_reshaper.reshape("يمكنك التحقق من السيارات المتوفرة في المخزون. هل تريد تفاصيل عن سيارة معينة؟"))
|
||||||
|
},
|
||||||
|
"bye": {
|
||||||
|
"en": "Goodbye! Let me know if you need further help.",
|
||||||
|
"ar": get_display(arabic_reshaper.reshape("وداعاً! أخبرني إذا كنت بحاجة إلى مزيد من المساعدة."))
|
||||||
|
},
|
||||||
|
"unknown": {
|
||||||
|
"en": "I'm sorry, I didn't understand that. Can you rephrase?",
|
||||||
|
"ar": get_display(arabic_reshaper.reshape("عذراً، لم أفهم ذلك. هل يمكنك إعادة صياغة السؤال؟"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to classify user input
|
||||||
|
def classify_message(message):
|
||||||
|
message = message.lower()
|
||||||
|
if re.search(r"hello|hi|مرحب|السلام", message):
|
||||||
|
return "greet"
|
||||||
|
elif re.search(r"sell|بيع", message):
|
||||||
|
return "sell_process"
|
||||||
|
elif re.search(r"inventory|cars|المخزون|السيارات", message):
|
||||||
|
return "inventory_check"
|
||||||
|
elif re.search(r"bye|وداع|إلى اللقاء", message):
|
||||||
|
return "bye"
|
||||||
|
else:
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
# Send response based on the intent
|
||||||
|
@bot.on_message()
|
||||||
|
def handle_message(message):
|
||||||
|
user_input = message.body.strip()
|
||||||
|
intent = classify_message(user_input)
|
||||||
|
|
||||||
|
# Detect language and respond
|
||||||
|
if re.search("[\u0600-\u06FF]", user_input): # Arabic characters
|
||||||
|
response = responses[intent]["ar"]
|
||||||
|
else: # Default to English
|
||||||
|
response = responses[intent]["en"]
|
||||||
|
|
||||||
|
message.reply(response)
|
||||||
|
|
||||||
|
# Start the bot
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Starting the Haikal Car Inventory WhatsApp Bot...")
|
||||||
|
bot.run()
|
||||||
Loading…
x
Reference in New Issue
Block a user