From 709b3359f39997b12d78a1997e50690875758f7c Mon Sep 17 00:00:00 2001 From: Marwan Alwali Date: Thu, 13 Feb 2025 11:11:32 +0300 Subject: [PATCH] update --- .DS_Store | Bin 18436 -> 18436 bytes .gitignore | 1 + .../__pycache__/settings.cpython-311.pyc | Bin 8488 -> 8687 bytes inventory/__pycache__/views.cpython-311.pyc | Bin 192017 -> 192404 bytes .../__pycache__/translate.cpython-311.pyc | Bin 2635 -> 2779 bytes inventory/management/commands/translate.py | 57 +++---- inventory/views.py | 23 +-- scripts/dsrpipe.py | 140 ++++++++++++++++++ .../sales/estimates/estimate_detail.html | 6 +- templates/sales/estimates/estimate_send.html | 4 +- .../estimates/payment_request_detail.html | 16 +- templates/sales/sales_list.html | 2 + templates/vendors/vendors_list.html | 39 +---- 13 files changed, 201 insertions(+), 87 deletions(-) create mode 100644 scripts/dsrpipe.py diff --git a/.DS_Store b/.DS_Store index 142e5f911c242edbbcd484d05067b1e375b766be..4e9a6ecabd5af35f6f701bcbc2818aa5c25bf4e4 100644 GIT binary patch delta 824 zcmd^*&r8#B9LD#0&$;E+Ayfw9en8m|WHJ!frh=s)mcll$?3)L1o`fB8+M!EM_)>Y> z_;``@7CU$u?(0Fa=rr*cm4_Yl&_%0@6bjo-NOZgT4@l4Db$Z}=J$ec~MJkN899i?= zGaO#0&Cu@Vtm$OHu=_ulm3E_76r+=A_OeH|5!a@zTG~&jCmwN;V5~7_R!bFJj zoDoKeF-DvTCYjs@Atc0Q2jbtW%Aw)nD4xr6d-DB!o_sS|GFh@KiCt~E zQH|gB)KrwtH>6YI5)i-iN{=KZAt~vSpq1=iA5V72MP!PIdMv_Z9jPs|eYF?dwqc%i zxr6n-nxMHzubbMS$AYW8{`l5pqBmulPf)ILCF9+t6DAs-Nz+@~TH8Gxy2m$aTXi7} z=VX3nN9JiyIGoPOh&-1U@=iX;NBJb5Q5cj_P6d_B!jDOS1uSM6Q7l%|P6sj8&`E;L zB-z3?cF|9o0rqnU%@K}roIx&fiOXE)9`|{`Lmu&zXN>ZaSG?v8V|;1ks}eO$%}`Zp zrZQDPg;k@9D(go|MImmiunSAYe%axGJy4%;HV0jKo)&?bGpykFZ( zs*60dq)iqQVW~se#B!QxD{!u*iw$hdv!>`{J3H9P9y07@pTm1N&wGp$oa8iTIL8oI zxQ5LzH@U@a?r_&JkYnUKeGyjkPb}@Nbn{jZ*X4?m{UaZ0*j=JS;W_^`|EUO}zb%69 Hn|tsZ2C@3C diff --git a/.gitignore b/.gitignore index 237f8bef..71c44dd4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ db.sqlite db.sqlite3 media car_inventory/settings.py +scripts/dsrpipe.py # Backup files # *.bak diff --git a/car_inventory/__pycache__/settings.cpython-311.pyc b/car_inventory/__pycache__/settings.cpython-311.pyc index eeca03800d6dcbe584a8ef7fa5db73ef576255fb..f8667ea2ceae73217ba596425fdcfb32f82db943 100644 GIT binary patch delta 462 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 M#)_}LrWEr(0lcUs#sB~S delta 2243 zcmZuy3viUx72faL-9Kcro82W3Vjc_O6@?T^Qa~QzF$Efl5DNjuB9CAYNhF1UrPd$; zX(9!YpzAcBC9LP>GAZdJfSrIrqgkW^Zb6z%;tjDwxt*}2(s?)lC+ z_w4uGti2Mo`je>W?Jk$YqSu(CyJmbic6D?D%Ing)IwPN)K5?7PV%ceXHP5N?ocQ+} zOti^~LS#tGbULKsadwdo4T$lSqvV}ZTY?z)_@sSVV|Js7iGNS=W za_17-O5;pAThXz_x*g{rx-|4~Ba+(|57$uV1L)vVR(bq${?V}&doq>}Vd2#$UBY#} zF7pcJDzy|um)fe@hCw%WBksFe?N$07Jc2ecCH-_$n;tacLp9E z8T90YJUIbRjvTAS80~p7=ouCAj0$*0nVuvWT!%P!pzBY9&g_sgI}rXzQ616{kbSl2 z`u_vI)B!r#=%6Pz3mccU0pE z3?lAH)G6FGJ~x9GwFdi6qrDY|8gvGGBJgAN<@=~+M0}KvsG{HdO}wi46E50}7fsJn z|D1dAQvDH5a&}a>wFMvJiAXG0zyB2XZ8)Y*UqcSjpuE=sJ3=bvCYD=qM>aO&Aez;< zf8r)+cgg@Ck|qB(=JVSqb@4V5tVXm`SE!Y&40e*FySNO8x_1}LY)Dp1?jzEQzUx-; zAbUCeCyvI6=WE#2RB%0zrS6ektr)IS4PLWiylUg%1{#HC!hCT#_^1jxImwE-s;7tV zL|~!1(T-_)9{%!{6e+XPC%K7SidW>LL^j42L~PSU*%?-pNk>@brARP|sWEQTG}i`8 zfuqv8z&0;c*^~K|4PN=W19N3mD)WrpX5sttE%}HXPvuHypyR+`o2*cqtU#MAmEV!I zG%lGjN6eT+8Dh|_hIFC+g__jDG~NXMrHUWZcQfvrVMD`XFG|oPPw&pFFvOkCP5469 zq_YNE&Qp4Dsvg(z9-MDQf_glI5kQO@l1UfQO-A?TI<4G4j$}L4(whf>9;&V{_Y=L< zbN#8gHA&tW$R&Dmsafw!XbYX}Rhcva;M)8fXQA}nmn!sE=%X}{1q;!P2<_aiks^E)6CTK5>Dg| zTvxXy>c;q)E6mPblXNR|M9Zop=qWOVe}Gp_o62G!R)YCFV=!9JS6aK+H;p5RPI9k+ zJ0rX4gOW76#o})|m88y2=Wl=?$Wt?T-AH-}Gxm8tXVqgoQbey^%cpTRzlp*ob*_|S zfI8)Sg}sQY>Zvkj5x-EY7BkZ@Zkic-%DY8OkSo7slWsq-jJNS0^G`eZWI2DNx#)e3 zBdnM8yS;g#eqI;8reEgn@qr%Sh}lD*tQ z*i`%h8UW<@VJ5472hDsP<7t`>Tl=tJKoi{6^8+Fasm N4m*aa{J$~N`CpX>)H(nF diff --git a/inventory/management/commands/__pycache__/translate.cpython-311.pyc b/inventory/management/commands/__pycache__/translate.cpython-311.pyc index cda4a7bd3dbc9323e76e2149f66a78fc1d19219e..d578167ba8a61aae3fe531e72d070479577e9afc 100644 GIT binary patch delta 1325 zcmb7DO>7%Q6rTOFcb(d?V;2&KI^zwkV+B%0g}9Kkp~Y!R!L?8YQY4DC^-jV%u^sKM zn}QrHaS9>_y8}w4wo(o#6g8D{=%ELMQYi-z7du)JE2t7D&KtEzQBTaQu?SEOJiYne zoA*Dnvp-7Lazm4CUdFZbBeh&EGRP;;pD636tS;f?fh1%1aMaC+irX(fijnKT2foC zqwQHe)YcA4)up;sQI&47s)y9^wtdtx!>S$Yht@a%UcXDAMT_pTJLhZfRBumP1vxsu zLpgt2TMgg{+wT_3VwulK_#N(4)K_+qV|6-*^WPTM7;-GKTEu|m6}-ts-wPZZhQxQ3 zrJLY3|Ig?tpn^r|Q)zj#B^Q_laE+S+3(WG5D!2sV!HaQb*R9NJnOXEPevMBE3PZYK zoljJziY2J%2r31r7=~t;O2LE%{W8j&_6bs119|bmfYcb#e_j zUDRP-nMKA+t&&6`@58!#+7| zN5IhmyC2AJFngfVB|rBB5U5_TkAeP|E%}v=cP%+#$>Wwhxg)2x2pGuo1k&^aq~uKq9HCuDQ93{_4zH^TjOUk3ee9-clcB}H~i^dv`wt*&r# zSlAjCh<-6H?1~xs(NHF{>&axuD=W?6FT`%|2+8{vJf^>k{wm%OW09ypM}0QxWB7OR zv+yX59&=I%JQc^Bdg!!%2G^uS<-~k2PUp}{fD{QxjG6-n4jfx4he}*_qiJIW3GIWfC#l<;-nr}uvI z=FQA|zulQ<($k=S$>$RR1@cvfS$^LCPe|(5N@phXxx)8_oHkvU7(b_tUd_+HnipH> zzEAW6`&+_ru^h7Ma3FCN~Q=x$W;|}09KGovYO4^k|E<3J` zsne9Y zh}2a-TOX_s66w&K*g%mr6kA0x6SWi6j(>1Rt4e46$dm63C1olpqNFS!2^rXAvn4v0 zsU5MHpf3X((S3I=lIY>JXzyyYw-IT#c+l}xBYxT9*l@%GHi@9)KqG$eesxFAE65=$ z2$V0ZFp&G61E0L>rA;-_Y6E){RU&sk3K01ak$Z{Uza|f?$^)i+lE^1(-bUhZO(bYP z)%|PhFRdn02vQ8BY#_-9UHYwq619c@$49e|tIf<`Bh8VriG~OoG8}uovAfLzkbcZI zS2NJ5)?fc-`CB8@Pwfxb98HuaC~drFuPH3nE@KCY?f*4pKg>T}ia!@V^QrXQL-4|Wd!?`OF(EETI9ue0xs=4W zgdZb)_U@!}gwm#` L`S~`IhQLW|-@CnucG2?Bs_$ahBe3<7(o;xcqKeAqO*~;Dk DGW0*V diff --git a/inventory/management/commands/translate.py b/inventory/management/commands/translate.py index 7bcd1b31..0ac7bd94 100644 --- a/inventory/management/commands/translate.py +++ b/inventory/management/commands/translate.py @@ -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}") diff --git a/inventory/views.py b/inventory/views.py index 6740f3f3..44401c15 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -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""" diff --git a/scripts/dsrpipe.py b/scripts/dsrpipe.py new file mode 100644 index 00000000..0526150c --- /dev/null +++ b/scripts/dsrpipe.py @@ -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 == "": + 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 "" + + if self.thinking == 0 and not delta.get("reasoning_content"): + self.thinking = 1 + return "\n\n\n" + + return "" diff --git a/templates/sales/estimates/estimate_detail.html b/templates/sales/estimates/estimate_detail.html index 125b9a13..a6ae6a38 100644 --- a/templates/sales/estimates/estimate_detail.html +++ b/templates/sales/estimates/estimate_detail.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% load i18n %} -{% block title %}{{ _("View Estimate") }}{% endblock title %} +{% block title %}{{ _("View Quotation") }}{% endblock title %} {% block content %} diff --git a/templates/sales/estimates/estimate_send.html b/templates/sales/estimates/estimate_send.html index 7091686a..4b9812b2 100644 --- a/templates/sales/estimates/estimate_send.html +++ b/templates/sales/estimates/estimate_send.html @@ -2,7 +2,7 @@ {% load crispy_forms_filters %} {% load i18n static %} -{% block title %}{{ _("Quotations") }}{% endblock title %} +{% block title %}{{ _("Quotation") }}{% endblock title %} {% block content %} - - {% endblock content %} \ No newline at end of file diff --git a/templates/sales/estimates/payment_request_detail.html b/templates/sales/estimates/payment_request_detail.html index 753999bd..fab876d2 100644 --- a/templates/sales/estimates/payment_request_detail.html +++ b/templates/sales/estimates/payment_request_detail.html @@ -106,24 +106,26 @@ نوع السيارة اللون الخارجي اللون الداخلي + السعر + ملاحظات {% for car in cars %} - {{ car.year }} - {{ car.id_car_make.arabic_name }} - {{ car.id_car_model.arabic_name }} - {{ car.id_car_trim.arabic_name }} - {{ car.colors.first.exterior.arabic_name }} - {{ car.colors.first.interior.arabic_name }} - {{ car.finances.first.cost_price }} - {{ car. }} + {{ car.year }} - {{ car.id_car_make.name }} - {{ car.id_car_model.name }} - {{ car.id_car_trim.name }} + {{ car.colors.first.exterior.name }} + {{ car.colors.first.interior.name }} + {{ car.finances.selling_price }} + {{ car.get_specifications }} {% endfor %} -

حمولة المركبة () سنة الصنع () (جديد / مستعملة) كلم/ميل

+

حمولة المركبة )) سنة الصنع () (جديد / مستعملة) كلم/ميل

-

مستوى اقتصاد الوقود () رقم الشاسيه (في حال كانت السيارة مستعملة فقط) ()

+

مستوى اقتصاد الوقود )) رقم الهيكل (في حال كانت السيارة مستعملة فقط) ()

مواصفات أخرى:

diff --git a/templates/sales/sales_list.html b/templates/sales/sales_list.html index f905d369..97bef0e6 100644 --- a/templates/sales/sales_list.html +++ b/templates/sales/sales_list.html @@ -238,7 +238,9 @@
+ {% if is_paginated %} {% include 'partials/pagination.html' %} + {% endif %}
diff --git a/templates/vendors/vendors_list.html b/templates/vendors/vendors_list.html index e1cf3176..d39f408f 100644 --- a/templates/vendors/vendors_list.html +++ b/templates/vendors/vendors_list.html @@ -114,7 +114,6 @@
{% endif %}
-
{{ vendor.vendor_name }}

{{ vendor.vendor_name }}

{{ vendor.id}} @@ -147,43 +146,7 @@
{% if is_paginated %} - +{% include 'partials/pagination.html' %} {% endif %}