update
This commit is contained in:
parent
0733ea3669
commit
709b3359f3
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ db.sqlite
|
||||
db.sqlite3
|
||||
media
|
||||
car_inventory/settings.py
|
||||
scripts/dsrpipe.py
|
||||
# Backup files #
|
||||
*.bak
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
from openai import OpenAI
|
||||
from django.core.management.base import BaseCommand
|
||||
from inventory.models import CarSerie, CarModel, CarMake, CarTrim, CarOption, CarSpecificationValue
|
||||
from inventory.models import CarSerie, CarModel, CarMake, CarTrim, CarOption, CarSpecification
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
@ -9,28 +9,35 @@ class Command(BaseCommand):
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
client = OpenAI(api_key=settings.OPENAI_API_KEY)
|
||||
car_option = CarOption.objects.all()[10300:]
|
||||
total = car_option.count()
|
||||
en_value = CarModel.objects.all()
|
||||
|
||||
total = en_value.count()
|
||||
print(f'Translating {total} names...')
|
||||
for index, car_option in enumerate(car_option, start=1):
|
||||
try:
|
||||
completion = client.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are an assistant that translates English to Arabic."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": car_option.name
|
||||
}
|
||||
],
|
||||
temperature=0.2,
|
||||
)
|
||||
translation = completion.choices[0].message.content.strip()
|
||||
car_option.arabic_name = translation
|
||||
car_option.save()
|
||||
print(f"[{index}/{total}] Translated '{car_option.name}' to '{translation}'")
|
||||
except Exception as e:
|
||||
print(f"Error translating '{car_option.name}': {e}")
|
||||
for index, en_value in enumerate(en_value, start=1):
|
||||
if not en_value.arabic_name:
|
||||
try:
|
||||
completion = client.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
"You are an assistant that translates English to Arabic."
|
||||
"You are an assistant specialized in cars and automotive terms."
|
||||
"If the model name is a number just write it as is"
|
||||
"You can get the arabic names for makes, models, series, trims, options, and specifications."
|
||||
)
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": en_value.name
|
||||
}
|
||||
],
|
||||
temperature=0.2,
|
||||
)
|
||||
translation = completion.choices[0].message.content.strip()
|
||||
en_value.arabic_name = translation
|
||||
en_value.save()
|
||||
print(f"[{index}/{total}] .. Done")
|
||||
except Exception as e:
|
||||
print(f"Error translating '{en_value.name}': {e}")
|
||||
|
||||
@ -2675,7 +2675,7 @@ class PaymentRequest(LoginRequiredMixin, DetailView):
|
||||
return context
|
||||
|
||||
|
||||
class EstimatePreviewView(LoginRequiredMixin, DetailView):
|
||||
class EstimatePreviewView(DetailView):
|
||||
model = EstimateModel
|
||||
context_object_name = "estimate"
|
||||
template_name = "sales/estimates/estimate_preview.html"
|
||||
@ -2697,30 +2697,31 @@ class EstimatePreviewView(LoginRequiredMixin, DetailView):
|
||||
@login_required
|
||||
def estimate_mark_as(request, pk):
|
||||
estimate = get_object_or_404(EstimateModel, pk=pk)
|
||||
entity = estimate.entity
|
||||
dealer = get_user_type(request.user)
|
||||
entity = dealer.entity
|
||||
mark = request.GET.get("mark")
|
||||
if mark:
|
||||
if mark == "review":
|
||||
if not estimate.can_review():
|
||||
messages.error(request, "Estimate is not ready for review")
|
||||
messages.error(request, _("Estimate is not ready for review"))
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
estimate.mark_as_review()
|
||||
|
||||
elif mark == "approved":
|
||||
if not estimate.can_approve():
|
||||
messages.error(request, "Estimate is not ready for approval")
|
||||
messages.error(request, _("Estimate is not ready for approval"))
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
estimate.mark_as_approved()
|
||||
messages.success(request, "Estimate approved successfully.")
|
||||
messages.success(request, _("Estimate approved successfully."))
|
||||
elif mark == "rejected":
|
||||
if not estimate.can_cancel():
|
||||
messages.error(request, "Estimate is not ready for rejection")
|
||||
messages.error(request, _("Estimate is not ready for rejection"))
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
estimate.mark_as_canceled()
|
||||
messages.success(request, "Estimate canceled successfully.")
|
||||
messages.success(request, _("Estimate canceled successfully."))
|
||||
elif mark == "completed":
|
||||
if not estimate.can_complete():
|
||||
messages.error(request, "Estimate is not ready for completion")
|
||||
messages.error(request, _("Estimate is not ready for completion"))
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
estimate.save()
|
||||
messages.success(request, "Estimate marked as " + mark.upper())
|
||||
@ -3257,7 +3258,7 @@ def send_lead_email(request, pk):
|
||||
request.POST.get("subject"),
|
||||
request.POST.get("message"),
|
||||
)
|
||||
messages.success(request, "Email sent successfully!")
|
||||
messages.success(request, _("Email sent successfully!"))
|
||||
return redirect("lead_list")
|
||||
msg = f"""
|
||||
السلام عليكم
|
||||
@ -3848,7 +3849,7 @@ def send_email_view(request, pk):
|
||||
# messages.error(request, "Estimate is not ready for review")
|
||||
# return redirect("estimate_detail", pk=estimate.pk)
|
||||
if not estimate.get_itemtxs_data()[0]:
|
||||
messages.error(request, "Estimate has no items")
|
||||
messages.error(request, _("Estimate has no items"))
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
|
||||
send_email(
|
||||
@ -3858,7 +3859,7 @@ def send_email_view(request, pk):
|
||||
request.POST.get("message"),
|
||||
)
|
||||
estimate.mark_as_review()
|
||||
messages.success(request, "Email sent successfully!")
|
||||
messages.success(request, _("Email sent successfully!"))
|
||||
return redirect("estimate_detail", pk=estimate.pk)
|
||||
link = reverse_lazy("estimate_preview", kwargs={"pk": estimate.pk})
|
||||
msg = f"""
|
||||
|
||||
140
scripts/dsrpipe.py
Normal file
140
scripts/dsrpipe.py
Normal file
@ -0,0 +1,140 @@
|
||||
"""
|
||||
title: Deepseek R1 Reasoner and Chat with Realtime Thinking Preview
|
||||
authors: Ethan Copping
|
||||
author_url: https://github.com/CoppingEthan
|
||||
version: 0.3.0
|
||||
required_open_webui_version: 0.5.5
|
||||
license: MIT
|
||||
# Acknowledgments
|
||||
Code used from MCode-Team & Zgccrui
|
||||
"""
|
||||
|
||||
import json
|
||||
import httpx
|
||||
from typing import AsyncGenerator, Callable, Awaitable
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Pipe:
|
||||
class Valves(BaseModel):
|
||||
DEEPSEEK_API_BASE_URL: str = Field(
|
||||
default="https://api.deepseek.com/v1", description="Base API endpoint URL"
|
||||
)
|
||||
DEEPSEEK_API_KEY: str = Field(
|
||||
default="", description="Authentication key for API access"
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.thinking = -1
|
||||
self._emitter = None
|
||||
self.data_prefix = "data: "
|
||||
|
||||
def pipes(self):
|
||||
try:
|
||||
headers = {"Authorization": f"Bearer {self.valves.DEEPSEEK_API_KEY}"}
|
||||
resp = httpx.get(
|
||||
f"{self.valves.DEEPSEEK_API_BASE_URL}/models",
|
||||
headers=headers,
|
||||
timeout=10,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
return [
|
||||
{"id": m["id"], "name": m["id"]}
|
||||
for m in resp.json().get("data", [])
|
||||
]
|
||||
except Exception:
|
||||
pass
|
||||
return [
|
||||
{"id": "deepseek-chat", "name": "deepseek-chat"},
|
||||
{"id": "deepseek-reasoner", "name": "deepseek-reasoner"},
|
||||
]
|
||||
|
||||
async def pipe(
|
||||
self, body: dict, __event_emitter__: Callable[[dict], Awaitable[None]] = None
|
||||
) -> AsyncGenerator[str, None]:
|
||||
self.thinking = -1
|
||||
self._emitter = __event_emitter__
|
||||
|
||||
if not self.valves.DEEPSEEK_API_KEY:
|
||||
yield json.dumps({"error": "Missing API credentials"})
|
||||
return
|
||||
|
||||
req_headers = {
|
||||
"Authorization": f"Bearer {self.valves.DEEPSEEK_API_KEY}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
try:
|
||||
request_data = body.copy()
|
||||
model_id = request_data["model"].split(".", 1)[-1]
|
||||
request_data["model"] = model_id
|
||||
is_reasoner = "reasoner" in model_id.lower()
|
||||
|
||||
messages = request_data["messages"]
|
||||
for i in reversed(range(1, len(messages))):
|
||||
if messages[i - 1]["role"] == messages[i]["role"]:
|
||||
alt_role = (
|
||||
"user" if messages[i]["role"] == "assistant" else "assistant"
|
||||
)
|
||||
messages.insert(
|
||||
i, {"role": alt_role, "content": "[Unfinished thinking]"}
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient(http2=True) as client:
|
||||
async with client.stream(
|
||||
"POST",
|
||||
f"{self.valves.DEEPSEEK_API_BASE_URL}/chat/completions",
|
||||
json=request_data,
|
||||
headers=req_headers,
|
||||
timeout=20,
|
||||
) as resp:
|
||||
if resp.status_code != 200:
|
||||
error_content = (await resp.aread()).decode()[:200]
|
||||
yield json.dumps(
|
||||
{"error": f"API error {resp.status_code}: {error_content}"}
|
||||
)
|
||||
return
|
||||
|
||||
async for line in resp.aiter_lines():
|
||||
if not line.startswith(self.data_prefix):
|
||||
continue
|
||||
|
||||
stream_data = json.loads(line[6:])
|
||||
choice = stream_data.get("choices", [{}])[0]
|
||||
|
||||
if choice.get("finish_reason"):
|
||||
return
|
||||
|
||||
delta = choice.get("delta", {})
|
||||
|
||||
if is_reasoner:
|
||||
state_marker = self._handle_state(delta)
|
||||
if state_marker:
|
||||
yield state_marker
|
||||
if state_marker == "<think>":
|
||||
yield "\n"
|
||||
|
||||
content = delta.get("reasoning_content", "") or delta.get(
|
||||
"content", ""
|
||||
)
|
||||
if content:
|
||||
yield content
|
||||
else:
|
||||
content = delta.get("content", "")
|
||||
if content:
|
||||
yield content
|
||||
|
||||
except Exception as e:
|
||||
yield json.dumps({"error": f"{type(e).__name__}: {str(e)}"})
|
||||
|
||||
def _handle_state(self, delta: dict) -> str:
|
||||
if self.thinking == -1 and delta.get("reasoning_content"):
|
||||
self.thinking = 0
|
||||
return "<think>"
|
||||
|
||||
if self.thinking == 0 and not delta.get("reasoning_content"):
|
||||
self.thinking = 1
|
||||
return "\n</think>\n\n"
|
||||
|
||||
return ""
|
||||
@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{{ _("View Estimate") }}{% endblock title %}
|
||||
{% block title %}{{ _("View Quotation") }}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="modal fade" id="confirmModal" tabindex="-1" aria-labelledby="confirmModalLabel" aria-hidden="true">
|
||||
@ -21,8 +21,8 @@
|
||||
<form id="confirmForm" method="POST" action="{% url 'estimate_mark_as' estimate.pk %}?mark=approved" class="form">
|
||||
{% csrf_token %}
|
||||
<div class="container-fluid m-0 p-0">
|
||||
<button type="button" class="btn btn-danger btn-sm w-100" data-bs-dismiss="modal">{% trans 'No' %}</button>
|
||||
<button type="submit" class="btn btn-success btn-sm w-100">{% trans "Yes" %}</button>
|
||||
<button type="button" class="btn btn-danger btn-sm" data-bs-dismiss="modal">{% trans 'No' %}</button>
|
||||
<button type="submit" class="btn btn-success btn-sm">{% trans "Yes" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
{% load crispy_forms_filters %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block title %}{{ _("Quotations") }}{% endblock title %}
|
||||
{% block title %}{{ _("Quotation") }}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card email-content">
|
||||
@ -30,7 +30,5 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
@ -106,24 +106,26 @@
|
||||
<th>نوع السيارة</th>
|
||||
<th>اللون الخارجي</th>
|
||||
<th>اللون الداخلي</th>
|
||||
<th>السعر</th>
|
||||
<th>ملاحظات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for car in cars %}
|
||||
<tr>
|
||||
<td>{{ car.year }} - {{ car.id_car_make.arabic_name }} - {{ car.id_car_model.arabic_name }} - {{ car.id_car_trim.arabic_name }}</td>
|
||||
<td>{{ car.colors.first.exterior.arabic_name }}</td>
|
||||
<td>{{ car.colors.first.interior.arabic_name }}</td>
|
||||
<td>{{ car.finances.first.cost_price }}</td>
|
||||
<td>{{ car. }}</td>
|
||||
<td>{{ car.year }} - {{ car.id_car_make.name }} - {{ car.id_car_model.name }} - {{ car.id_car_trim.name }}</td>
|
||||
<td>{{ car.colors.first.exterior.name }}</td>
|
||||
<td>{{ car.colors.first.interior.name }}</td>
|
||||
<td>{{ car.finances.selling_price }}</td>
|
||||
<td>{{ car.get_specifications }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>حمولة المركبة (<input type="text">) سنة الصنع (<input type="text">) (جديد / مستعملة) كلم/ميل</p>
|
||||
<p>حمولة المركبة )<input type="text">) سنة الصنع (<input type="text">) (جديد / مستعملة) كلم/ميل</p>
|
||||
|
||||
<p>مستوى اقتصاد الوقود (<input type="text">) رقم الشاسيه (في حال كانت السيارة مستعملة فقط) (<input type="text">)</p>
|
||||
<p>مستوى اقتصاد الوقود )<input type="text">) رقم الهيكل (في حال كانت السيارة مستعملة فقط) (<input type="text">)</p>
|
||||
|
||||
<p>مواصفات أخرى:</p>
|
||||
<input type="text">
|
||||
|
||||
@ -238,7 +238,9 @@
|
||||
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between py-3 pe-0 fs-9 border-bottom border-translucent">
|
||||
<div class="d-flex">
|
||||
{% if is_paginated %}
|
||||
{% include 'partials/pagination.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
39
templates/vendors/vendors_list.html
vendored
39
templates/vendors/vendors_list.html
vendored
@ -114,7 +114,6 @@
|
||||
<div class="avatar avatar-xl me-3"><img class="rounded-circle" src="{% static 'images/icons/picture.svg' %}" alt="" />
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div><a class="fs-8 fw-bold" href="">{{ vendor.vendor_name }}</a>
|
||||
<div class="d-flex align-items-center">
|
||||
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ vendor.vendor_name }}</p><span class="badge badge-phoenix badge-phoenix-primary">{{ vendor.id}}</span>
|
||||
@ -147,43 +146,7 @@
|
||||
<div class="row align-items-center justify-content-end py-4 pe-0 fs-9">
|
||||
<!-- Optional: Pagination -->
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination mb-0">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item py-0">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
|
||||
<span aria-hidden="true"><span class="fas fa-chevron-left"></span></span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Previous">
|
||||
<span aria-hidden="true"><span class="fas fa-chevron-left"></span></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
|
||||
{% else %}
|
||||
<li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
|
||||
<span aria-hidden="true"><span class="fas fa-chevron-right"></span></span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" aria-label="Next">
|
||||
<span aria-hidden="true"><span class="fas fa-chevron-right"></span></span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% include 'partials/pagination.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user