From b82eb093915f8a1275a0e1b8190800314357e14f Mon Sep 17 00:00:00 2001 From: nicolas-entourage <75681929+nicolas-entourage@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:23:24 +0100 Subject: [PATCH] EN-7354 openai assistants are configured as active_records --- ...nai_assistant_configurations_controller.rb | 45 ++++++++++++++ app/models/openai_assistant_configuration.rb | 2 + app/services/matching_services/connect.rb | 59 ++++++++++++++----- .../_edit_header.html.erb | 13 ++++ .../_form.html.erb | 50 ++++++++++++++++ .../edit.html.erb | 4 ++ .../index.html.erb | 36 +++++++++++ app/views/layouts/_admin_header.html.erb | 1 + config/routes.rb | 2 + ..._create_openai_assistant_configurations.rb | 19 ++++++ ...openai_assistant_configuration_instance.rb | 18 ++++++ db/schema.rb | 13 ++++ spec/rails_helper.rb | 3 + 13 files changed, 249 insertions(+), 16 deletions(-) create mode 100644 app/controllers/admin/openai_assistant_configurations_controller.rb create mode 100644 app/models/openai_assistant_configuration.rb create mode 100644 app/views/admin/openai_assistant_configurations/_edit_header.html.erb create mode 100644 app/views/admin/openai_assistant_configurations/_form.html.erb create mode 100644 app/views/admin/openai_assistant_configurations/edit.html.erb create mode 100644 app/views/admin/openai_assistant_configurations/index.html.erb create mode 100644 db/migrate/20241127115900_create_openai_assistant_configurations.rb create mode 100644 db/migrate/20241127115901_create_openai_assistant_configuration_instance.rb diff --git a/app/controllers/admin/openai_assistant_configurations_controller.rb b/app/controllers/admin/openai_assistant_configurations_controller.rb new file mode 100644 index 000000000..860b24d0a --- /dev/null +++ b/app/controllers/admin/openai_assistant_configurations_controller.rb @@ -0,0 +1,45 @@ +module Admin + class OpenaiAssistantConfigurationsController < Admin::BaseController + layout 'admin_large' + + before_action :set_openai_assistant_configuration, only: [:edit, :update] + + def index + @openai_assistant_configurations = OpenaiAssistantConfiguration.all + .order(:version) + .page(page) + .per(per) + end + + def edit + end + + def update + @openai_assistant_configuration.assign_attributes(openai_assistant_configuration_params) + + if @openai_assistant_configuration.save + redirect_to edit_admin_openai_assistant_configuration_path(@openai_assistant_configuration) + else + render :edit + end + end + + private + + def set_openai_assistant_configuration + @openai_assistant_configuration = OpenaiAssistantConfiguration.find(params[:id]) + end + + def openai_assistant_configuration_params + params.require(:openai_assistant_configuration).permit(:prompt, :days_for_actions, :days_for_outings, :poi_from_file, :resource_from_file) + end + + def page + params[:page] || 1 + end + + def per + params[:per] || 25 + end + end +end diff --git a/app/models/openai_assistant_configuration.rb b/app/models/openai_assistant_configuration.rb new file mode 100644 index 000000000..ae5944e2c --- /dev/null +++ b/app/models/openai_assistant_configuration.rb @@ -0,0 +1,2 @@ +class OpenaiAssistantConfiguration < ApplicationRecord +end diff --git a/app/services/matching_services/connect.rb b/app/services/matching_services/connect.rb index 353a3ab59..5e6c2b69a 100644 --- a/app/services/matching_services/connect.rb +++ b/app/services/matching_services/connect.rb @@ -1,6 +1,6 @@ module MatchingServices class Connect - attr_reader :client, :callback, :assistant_id, :instance, :user + attr_reader :configuration, :client, :callback, :assistant_id, :instance, :user class MatcherCallback < Callback end @@ -8,8 +8,10 @@ class MatcherCallback < Callback def initialize instance: @callback = MatcherCallback.new - @client = OpenAI::Client.new(access_token: ENV['OPENAI_API_KEY']) - @assistant_id = ENV['OPENAI_API_ASSISTANT_ID_2'] + @configuration = OpenaiAssistantConfiguration.find_by_version(1) + + @client = OpenAI::Client.new(access_token: @configuration.api_key) + @assistant_id = @configuration.assistant_id @instance = instance @user = instance.user @@ -71,22 +73,26 @@ def find_run_message(thread_id, run_id) end def user_message + { + role: "user", + content: [ + { type: "text", text: get_formatted_prompt }, + { type: "text", text: get_recommandations.to_json } + ] + } + end + + def get_formatted_prompt instance_class = if instance.respond_to?(:action) && instance.action? instance.contribution? ? 'contribution' : 'solicitation' else instance.class.name.camelize.downcase end - { - role: "user", - content: [{ - type: "text", - text: "I created a #{instance_class} \"#{instance.name}\" : #{instance.description}. What are the most relevant recommandations? The following text contains all the possible recommandations." - }, { - type: "text", - text: get_recommandations.to_json - }] - } + @configuration.prompt + .gsub("{{action_type}}", instance_class) + .gsub("{{name}}", instance.name) + .gsub("{{description}}", instance.description) end def get_recommandations @@ -102,17 +108,38 @@ def get_recommandations def get_contributions return [] if instance.is_a?(Entourage) && instance.contribution? - ContributionServices::Finder.new(user, Hash.new).find_all.limit(100) + ContributionServices::Finder.new(user, Hash.new) + .find_all + .where("created_at > ?", @configuration.days_for_actions.days.ago) + .limit(100) end def get_solicitations return [] if instance.is_a?(Entourage) && instance.solicitation? - SolicitationServices::Finder.new(user, Hash.new).find_all.limit(100) + SolicitationServices::Finder.new(user, Hash.new) + .find_all + .where("created_at > ?", @configuration.days_for_actions.days.ago) + .limit(100) end def get_outings - OutingsServices::Finder.new(user, Hash.new).find_all.limit(100) + OutingsServices::Finder.new(user, Hash.new) + .find_all + .between(Time.zone.now, @configuration.days_for_outings.days.from_now) + .limit(100) + end + + def get_pois + return unless @configuration.poi_from_file + + Poi.validated.around(instance.latitude, instance.longitude, user.travel_distance).limit(300) + end + + def get_resources + return unless @configuration.resource_from_file + + Resource.where(status: :active) end end end diff --git a/app/views/admin/openai_assistant_configurations/_edit_header.html.erb b/app/views/admin/openai_assistant_configurations/_edit_header.html.erb new file mode 100644 index 000000000..a623580b4 --- /dev/null +++ b/app/views/admin/openai_assistant_configurations/_edit_header.html.erb @@ -0,0 +1,13 @@ +
+ + +

+ # Version <%= @openai_assistant_configuration.version %> +

+
diff --git a/app/views/admin/openai_assistant_configurations/_form.html.erb b/app/views/admin/openai_assistant_configurations/_form.html.erb new file mode 100644 index 000000000..51514cd04 --- /dev/null +++ b/app/views/admin/openai_assistant_configurations/_form.html.erb @@ -0,0 +1,50 @@ + + +<%= render partial: 'common/errors', locals: { obj: @openai_assistant_configuration } %> + +<%= form_for [:admin, @openai_assistant_configuration], html: { role: "form" } do |f| %> +
+ <%= f.label :prompt %> +
+ <%= f.text_area :prompt, class: "form-control", required: true %> +
+ {{action_type}} : en fonction de l'action créée par l'utilisateur, sera remplacé par "contribution" ou "solicitation"
+ {{name}} : nom de l'action créée par l'utilisateur
+ {{description}} : description de l'action créée par l'utilisateur
+
+ +
+ <%= f.label :days_for_actions %> +
+ <%= f.number_field :days_for_actions, class: "form-control", required: true %> +
+
+ +
+ <%= f.label :days_for_outings %> +
+ <%= f.number_field :days_for_outings, class: "form-control", required: true %> +
+
+ +
+ <%= f.label :poi_from_file, "Charger les points d'intérêt depuis un fichier ?" %> +
+ <%= f.radio_button :poi_from_file, true %> Oui + <%= f.radio_button :poi_from_file, false %> Non +
+
+ +
+ <%= f.label :resource_from_file, "Charger les ressources pédagogiques depuis un fichier ?" %> +
+ <%= f.radio_button :resource_from_file, true %> Oui + <%= f.radio_button :resource_from_file, false %> Non +
+
+ + <%= f.submit 'Enregistrer', class: "btn btn-primary" %> + <%= link_to "Retour", admin_openai_assistant_configurations_path, class: "btn btn-default" %> +<% end %> diff --git a/app/views/admin/openai_assistant_configurations/edit.html.erb b/app/views/admin/openai_assistant_configurations/edit.html.erb new file mode 100644 index 000000000..77d53a80c --- /dev/null +++ b/app/views/admin/openai_assistant_configurations/edit.html.erb @@ -0,0 +1,4 @@ +
+ <%= render 'edit_header', tab: :edit %> + <%= render partial: 'form' %> +
diff --git a/app/views/admin/openai_assistant_configurations/index.html.erb b/app/views/admin/openai_assistant_configurations/index.html.erb new file mode 100644 index 000000000..2398f383b --- /dev/null +++ b/app/views/admin/openai_assistant_configurations/index.html.erb @@ -0,0 +1,36 @@ +
+
+

openai_assistant_configuration

+ +
+ <% unless @openai_assistant_configurations.none? %> + + + + + + + + + + <% @openai_assistant_configurations.each_with_index do |openai_assistant_configuration, i| %> + <% parite = i.even? ? 'pair' : 'impair' %> + + + + + + + + + <% end %> +
VersionPromptpoi_from_fileresource_from_filedays_for_actionsdays_for_outings
<%= link_to openai_assistant_configuration.version, edit_admin_openai_assistant_configuration_path(openai_assistant_configuration) %><%= link_to openai_assistant_configuration.prompt, edit_admin_openai_assistant_configuration_path(openai_assistant_configuration) %><%= openai_assistant_configuration.poi_from_file %><%= openai_assistant_configuration.resource_from_file %><%= openai_assistant_configuration.days_for_actions %><%= openai_assistant_configuration.days_for_outings %>
+ <% end %> +
+ + <%= page_entries_info @openai_assistant_configurations, entry_name: 'openai_assistant_configurations' %> +
+ <%= paginate(@openai_assistant_configurations) %> +
+
+
diff --git a/app/views/layouts/_admin_header.html.erb b/app/views/layouts/_admin_header.html.erb index db4875213..25d84256d 100644 --- a/app/views/layouts/_admin_header.html.erb +++ b/app/views/layouts/_admin_header.html.erb @@ -19,6 +19,7 @@ Superadmin