diff --git a/config/settings/base.py b/config/settings/base.py index 829b23275..ce1275411 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -876,3 +876,13 @@ OPENAI_API_BASE = env.str("OPENAI_API_BASE", "") OPENAI_API_KEY = env.str("OPENAI_API_KEY", "") OPENAI_MODEL = env.str("OPENAI_MODEL", "") + + +# ELASTICSEARCH +# ------------------------------------------------------------------------------ +ELASTICSEARCH_SCHEME = env.str("ELASTICSEARCH_SCHEME", "https") +ELASTICSEARCH_HOST = env.str("ELASTICSEARCH_HOST", "") +ELASTICSEARCH_PORT = env.str("ELASTICSEARCH_PORT", "443") +ELASTICSEARCH_USERNAME = env.str("ELASTICSEARCH_USERNAME", "") +ELASTICSEARCH_PASSWORD = env.str("ELASTICSEARCH_PASSWORD", "") +ELASTICSEARCH_INDEX_SIAES = env.str("ELASTICSEARCH_INDEX_SIAES", "") diff --git a/env.default.sh b/env.default.sh index 2c441fab5..ae31bf993 100644 --- a/env.default.sh +++ b/env.default.sh @@ -28,3 +28,10 @@ export OPENAI_ORG="" export OPENAI_API_BASE="" export OPENAI_API_KEY="" export OPENAI_MODEL="" + +# ELASTICSEARCH +# ######################## +export ELASTICSEARCH_HOST= +export ELASTICSEARCH_USERNAME= +export ELASTICSEARCH_PASSWORD= +export ELASTICSEARCH_INDEX_SIAES= diff --git a/env.docker_default.local b/env.docker_default.local index 69b893fa9..0a7f66366 100755 --- a/env.docker_default.local +++ b/env.docker_default.local @@ -53,3 +53,10 @@ OPENAI_ORG= OPENAI_API_BASE= OPENAI_API_BASE= OPENAI_MODEL= + +# ELASTICSEARCH +# ######################## +ELASTICSEARCH_HOST= +ELASTICSEARCH_USERNAME= +ELASTICSEARCH_PASSWORD= +ELASTICSEARCH_INDEX_SIAES= diff --git a/lemarche/siaes/management/commands/put_siaes_in_elasticsearch_index.py b/lemarche/siaes/management/commands/put_siaes_in_elasticsearch_index.py new file mode 100644 index 000000000..b24d9ad20 --- /dev/null +++ b/lemarche/siaes/management/commands/put_siaes_in_elasticsearch_index.py @@ -0,0 +1,39 @@ +import time + +from django.conf import settings +from django.db.models import TextField +from django.db.models.functions import Length +from langchain.embeddings.openai import OpenAIEmbeddings +from langchain.vectorstores import ElasticVectorSearch + +from lemarche.siaes.models import Siae +from lemarche.utils.apis.api_elasticsearch import URL_WITH_USER +from lemarche.utils.commands import BaseCommand + + +class Command(BaseCommand): + help = "" + + def handle(self, *args, **options): + self.stdout_success("put siae to elasticsearch index started..") + + # Elasticsearch as a vector db + embeddings = OpenAIEmbeddings() + db = ElasticVectorSearch( + embedding=embeddings, elasticsearch_url=URL_WITH_USER, index_name=settings.ELASTICSEARCH_INDEX_SIAES + ) + + # Siaes with completed description + TextField.register_lookup(Length) # at least 10 characters + siaes = Siae.objects.filter(description__length__gt=9).all() + + for siae in siaes: + db.from_texts( + [siae.elasticsearch_index_text], + metadatas=[siae.elasticsearch_index_metadata], + embedding=embeddings, + elasticsearch_url=URL_WITH_USER, + index_name=settings.ELASTICSEARCH_INDEX_SIAES, + ) + time.sleep(1) + self.stdout_success(f"{siae.name} added !") diff --git a/lemarche/siaes/models.py b/lemarche/siaes/models.py index adcdc1e25..6e427f4bf 100644 --- a/lemarche/siaes/models.py +++ b/lemarche/siaes/models.py @@ -1134,6 +1134,20 @@ def latest_activity_at(self): latest_activity_at = self.updated_at return latest_activity_at + @property + def elasticsearch_index_text(self): + text = self.description + if self.offers.count() > 0: + offers = "\n\nPrestations:\n" + for offer in self.offers.all(): + offers += f"- {offer.name}:\n{offer.description}\n\n" + text += offers + return text + + @property + def elasticsearch_index_metadata(self): + return {"id": self.id, "name": self.name, "website": self.website if self.website else ""} + def sectors_list_string(self, display_max=3): sectors_name_list = self.sectors.form_filter_queryset().values_list("name", flat=True) if display_max and len(sectors_name_list) > display_max: diff --git a/lemarche/static/img/spinner-bars.svg b/lemarche/static/img/spinner-bars.svg new file mode 100644 index 000000000..1c3ec2e80 --- /dev/null +++ b/lemarche/static/img/spinner-bars.svg @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/lemarche/static/itou_marche/base/_custom.scss b/lemarche/static/itou_marche/base/_custom.scss index a79ff5278..b037e507c 100644 --- a/lemarche/static/itou_marche/base/_custom.scss +++ b/lemarche/static/itou_marche/base/_custom.scss @@ -98,3 +98,12 @@ a.disabled { .form-description-ckeditor .django-ckeditor-widget { width: 100%; } + +.htmx-indicator{ + opacity:0; + transition: opacity 500ms ease-in; +} + +.htmx-request .htmx-indicator{ + opacity:1 +} diff --git a/lemarche/templates/siaes/_si_ideas_search_result.html b/lemarche/templates/siaes/_si_ideas_search_result.html new file mode 100644 index 000000000..69ab8614c --- /dev/null +++ b/lemarche/templates/siaes/_si_ideas_search_result.html @@ -0,0 +1,35 @@ +
+ + + + + Le prestataire est trop petit pour répondre à mon besoin… + Mais il est sûrement ouvert à la co-traitance. + +
++ + + + + Son chiffre d'affaires est trop bas et je ne veux pas être + son seul client… Mais Vous pouvez commencer par lui confier + un marché de plus faible périmètre, sans prendre de risque, + puis faire grandir ce partenariat si vous en êtes satisfait. + +
++ + + + + L'offre ne correspond pas exactement à ce que je cherche… + Heureusement les entreprises sociales inclusives sont très + innovantes et s'adaptent à vos besoins. + +
+- - - - - Le prestataire est trop petit pour répondre à mon besoin… - Mais il est sûrement ouvert à la co-traitance. - -
-- - - - - Son chiffre d'affaires est trop bas et je ne veux pas être - son seul client… Mais Vous pouvez commencer par lui confier - un marché de plus faible périmètre, sans prendre de risque, - puis faire grandir ce partenariat si vous en êtes satisfait. - -
-- - - - - L'offre ne correspond pas exactement à ce que je cherche… - Heureusement les entreprises sociales inclusives sont très - innovantes et s'adaptent à vos besoins. - -
-Il y a encore de l'espoir ❤️
+Publiez votre besoin, et on s'occupe de vous trouver des prestataires inclusifs.
+Obtenez des réponses en moins de 24 heures (en moyenne).
+ + Publier un besoin d'achat + + {% endif %} +