From 4bfd1724ecc36f347e001afbcc94bc47c055949d Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Tue, 10 Dec 2024 10:51:50 -0500 Subject: [PATCH 01/14] Add test language model button --- .../settings/language_models_controller.rb | 8 ++++++- app/models/language_model.rb | 4 ++++ app/services/ai_backend.rb | 1 + app/services/ai_backend/anthropic.rb | 12 +++++++++++ app/services/ai_backend/open_ai.rb | 14 +++++++++++++ .../settings/language_models/_form.html.erb | 21 ++++++++++++++++++- 6 files changed, 58 insertions(+), 2 deletions(-) diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index 5c99396f..89b564c3 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -27,7 +27,13 @@ def create end def update - if @language_model.update(language_model_params) + if params[:test_language_model] + answer = @language_model.test_api + # TODO: Remove this and add testing route and turbo stream update + redirect_to settings_language_models_path, notice: "Test result: #{answer}", status: :see_other + #flash.now[:notice] = "Test result: #{answer}" + #render :edit, status: :unprocessable_entity + elsif @language_model.update(language_model_params) redirect_to settings_language_models_path, notice: "Saved", status: :see_other else render :edit, status: :unprocessable_entity diff --git a/app/models/language_model.rb b/app/models/language_model.rb index a0e48e8d..4fb758b5 100644 --- a/app/models/language_model.rb +++ b/app/models/language_model.rb @@ -31,6 +31,10 @@ def supports_tools? api_service.name != "Groq" # TODO: Remove this short circuit once I can debug tool use with Groq end + def test_api + ai_backend.test_language_model(self) + end + private def populate_position diff --git a/app/services/ai_backend.rb b/app/services/ai_backend.rb index d4204f08..f92142da 100644 --- a/app/services/ai_backend.rb +++ b/app/services/ai_backend.rb @@ -2,6 +2,7 @@ class AIBackend include Utilities, Tools attr :client + attr :test_language_model def initialize(user, assistant, conversation = nil, message = nil) @user = user diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index f8a4d5d9..6709e034 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -25,6 +25,18 @@ def initialize(user, assistant, conversation = nil, message = nil) end end + def self.test_language_model(language_model) + client = ::Anthropic::Client.new(uri_base: language_model.api_service.url, access_token: language_model.api_service.effective_token) + + # client.messages(parameters: { + # model: language_model.api_name, + # messages: [{ role: "user", content: "Hello!" }], + # }).dig("content", 0, "text") + "Not Implemented" + rescue ::Faraday::Error => e + e.message + end + private def client_method_name diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index aa8bd600..37f85d2f 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -25,6 +25,20 @@ def initialize(user, assistant, conversation = nil, message = nil) end end + def self.test_language_model(language_model) + client = ::OpenAI::Client.new( + access_token: language_model.api_service.effective_token, + uri_base: language_model.api_service.url + ) + + client.chat(parameters: { + model: language_model.api_name, + messages: [{ role: "user", content: "Hello!" }], + }).dig("choices", 0, "message", "content") + rescue ::Faraday::Error => e + e.message + end + private def client_method_name diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index d8ee22f2..248cd936 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -57,7 +57,26 @@ <%= form.check_box :supports_system_message %> <%= form.label :supports_system_message, "Supports System Message (Instructions)?" %> - +
+ <%= form.submit "Test", + name: "test_language_model", + class: %| + inline-block font-bold + bg-gray-200 dark:bg-gray-900 + border border-gray-400 + rounded-lg py-3 px-5 + cursor-pointer + |, + data: { turbo_submits_with: "Testing..." } + %> + + + +
<%= form.submit "Save", class: %| inline-block font-bold From 461a1230a73f8d651b82a3ee2d958527289a4611 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Wed, 11 Dec 2024 11:56:29 -0500 Subject: [PATCH 02/14] Test using form --- .../settings/language_models_controller.rb | 14 +++---- app/models/language_model.rb | 2 +- .../settings/language_models/_form.html.erb | 41 ++++++++++--------- config/routes.rb | 4 +- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index 89b564c3..28bb3c1e 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -27,19 +27,19 @@ def create end def update - if params[:test_language_model] - answer = @language_model.test_api - # TODO: Remove this and add testing route and turbo stream update - redirect_to settings_language_models_path, notice: "Test result: #{answer}", status: :see_other - #flash.now[:notice] = "Test result: #{answer}" - #render :edit, status: :unprocessable_entity - elsif @language_model.update(language_model_params) + if @language_model.update(language_model_params) redirect_to settings_language_models_path, notice: "Saved", status: :see_other else render :edit, status: :unprocessable_entity end end + def test + @language_model = Current.user.language_models.find_by(id: params[:language_model_id]) + @answer = @language_model.test + render :edit + end + def destroy @language_model.deleted! redirect_to settings_language_models_path, notice: "Deleted", status: :see_other diff --git a/app/models/language_model.rb b/app/models/language_model.rb index 4fb758b5..a1335842 100644 --- a/app/models/language_model.rb +++ b/app/models/language_model.rb @@ -31,7 +31,7 @@ def supports_tools? api_service.name != "Groq" # TODO: Remove this short circuit once I can debug tool use with Groq end - def test_api + def test ai_backend.test_language_model(self) end diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 248cd936..a7081bf6 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -57,26 +57,6 @@ <%= form.check_box :supports_system_message %> <%= form.label :supports_system_message, "Supports System Message (Instructions)?" %> -
- <%= form.submit "Test", - name: "test_language_model", - class: %| - inline-block font-bold - bg-gray-200 dark:bg-gray-900 - border border-gray-400 - rounded-lg py-3 px-5 - cursor-pointer - |, - data: { turbo_submits_with: "Testing..." } - %> - - - -
<%= form.submit "Save", class: %| inline-block font-bold @@ -87,4 +67,25 @@ |, data: { turbo_submits_with: "Saving..." } %> + <% if @answer %> +
Tested <%= @answer %>
+ <% else %> + <%= form.label :test, "Test", + class: %| + inline-block font-medium + bg-gray-100 dark:bg-gray-900 dark:text-white + border border-gray-400 + rounded-lg py-3 px-5 + cursor-pointer + | + %> + <% end %> <% end %> + +<%= button_to "Test", + settings_language_model_test_path(@language_model), + id: "language_model_test", + method: :get, + data: { turbo: false }, + class: "hidden" +%> diff --git a/config/routes.rb b/config/routes.rb index 73386abb..17a08926 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,7 +16,9 @@ namespace :settings do resources :assistants, except: [:index, :show] resource :person, only: [:edit, :update] - resources :language_models + resources :language_models do + get :test, to: "language_models#test" + end resources :api_services, except: [:show] resources :memories, only: [:index, :destroy] do delete :destroy, to: "memories#destroy_all", on: :collection From cc5664953e6d38d5c481790b274c0dbe6a58ece5 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Wed, 11 Dec 2024 13:29:49 -0500 Subject: [PATCH 03/14] Switch to turbo frame --- .../settings/language_models_controller.rb | 1 - .../settings/language_models/_form.html.erb | 23 +------------------ .../settings/language_models/edit.html.erb | 4 ++++ .../settings/language_models/test.html.erb | 9 ++++++++ 4 files changed, 14 insertions(+), 23 deletions(-) create mode 100644 app/views/settings/language_models/test.html.erb diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index 28bb3c1e..0beaa7e8 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -37,7 +37,6 @@ def update def test @language_model = Current.user.language_models.find_by(id: params[:language_model_id]) @answer = @language_model.test - render :edit end def destroy diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index a7081bf6..8494f87a 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -67,25 +67,4 @@ |, data: { turbo_submits_with: "Saving..." } %> - <% if @answer %> -
Tested <%= @answer %>
- <% else %> - <%= form.label :test, "Test", - class: %| - inline-block font-medium - bg-gray-100 dark:bg-gray-900 dark:text-white - border border-gray-400 - rounded-lg py-3 px-5 - cursor-pointer - | - %> - <% end %> -<% end %> - -<%= button_to "Test", - settings_language_model_test_path(@language_model), - id: "language_model_test", - method: :get, - data: { turbo: false }, - class: "hidden" -%> +<% end%> diff --git a/app/views/settings/language_models/edit.html.erb b/app/views/settings/language_models/edit.html.erb index 78d7a8b1..2e8eea8f 100644 --- a/app/views/settings/language_models/edit.html.erb +++ b/app/views/settings/language_models/edit.html.erb @@ -23,3 +23,7 @@ <%= link_to "Back", settings_language_models_path, class: "float-right inline-block ml-5 py-3" %>

+ +<%= link_to settings_language_model_test_path(@language_model), method: :get, data: { turbo_frame: :language_model_test } do %> + Test +<% end %> diff --git a/app/views/settings/language_models/test.html.erb b/app/views/settings/language_models/test.html.erb new file mode 100644 index 00000000..74ff069b --- /dev/null +++ b/app/views/settings/language_models/test.html.erb @@ -0,0 +1,9 @@ + <%= turbo_frame_tag :language_model_test do %> +
+ <% if @answer %> +
Tested <%= @answer %>
+ <% else %> +
Failed
+ <% end %> +
+ <% end %> From e887c0577c840ccae32dd69485aec62eb1741c12 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Wed, 11 Dec 2024 15:29:23 -0500 Subject: [PATCH 04/14] WIP. Finish test for openai --- app/services/ai_backend/anthropic.rb | 13 +++++++++---- app/services/ai_backend/gemini.rb | 4 ++++ app/services/ai_backend/open_ai.rb | 1 + app/views/settings/language_models/_form.html.erb | 4 ++++ app/views/settings/language_models/edit.html.erb | 4 ---- app/views/settings/language_models/test.html.erb | 4 ++-- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index 6709e034..7a0bcaf1 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -26,13 +26,18 @@ def initialize(user, assistant, conversation = nil, message = nil) end def self.test_language_model(language_model) - client = ::Anthropic::Client.new(uri_base: language_model.api_service.url, access_token: language_model.api_service.effective_token) + client = ::Anthropic::Client.new( + uri_base: language_model.api_service.url, + access_token: language_model.api_service.effective_token + ) - # client.messages(parameters: { + # TODO: Implement this. Use get_oneoff_message? + # client.chat(parameters: { # model: language_model.api_name, # messages: [{ role: "user", content: "Hello!" }], - # }).dig("content", 0, "text") - "Not Implemented" + # }).dig("choices", 0, "message", "content") + + "Testing Not Implemented Yet" rescue ::Faraday::Error => e e.message end diff --git a/app/services/ai_backend/gemini.rb b/app/services/ai_backend/gemini.rb index f89447cf..e9ef49ae 100644 --- a/app/services/ai_backend/gemini.rb +++ b/app/services/ai_backend/gemini.rb @@ -87,6 +87,10 @@ def stream_next_conversation_message(&chunk_handler) return nil end + def self.test_language_model(language_model) + "Testing Not Implemented Yet" + end + private def system_message(content) diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index 37f85d2f..1f36c56b 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -35,6 +35,7 @@ def self.test_language_model(language_model) model: language_model.api_name, messages: [{ role: "user", content: "Hello!" }], }).dig("choices", 0, "message", "content") + rescue ::Faraday::Error => e e.message end diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 8494f87a..8f8905dc 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -18,6 +18,10 @@
<%= form.label :api_name %> + <%= turbo_frame_tag :language_model_test, class: "inline-block" do %> + <%= link_to "Test", settings_language_model_test_path(@language_model), class: "inline-block ml-5 py-3" %> + <%= render template: "settings/language_models/test" %> + <% end %> <%= form.text_field :api_name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> As specified in the API docs
diff --git a/app/views/settings/language_models/edit.html.erb b/app/views/settings/language_models/edit.html.erb index 2e8eea8f..78d7a8b1 100644 --- a/app/views/settings/language_models/edit.html.erb +++ b/app/views/settings/language_models/edit.html.erb @@ -23,7 +23,3 @@ <%= link_to "Back", settings_language_models_path, class: "float-right inline-block ml-5 py-3" %>

- -<%= link_to settings_language_model_test_path(@language_model), method: :get, data: { turbo_frame: :language_model_test } do %> - Test -<% end %> diff --git a/app/views/settings/language_models/test.html.erb b/app/views/settings/language_models/test.html.erb index 74ff069b..4fba821f 100644 --- a/app/views/settings/language_models/test.html.erb +++ b/app/views/settings/language_models/test.html.erb @@ -1,9 +1,9 @@ <%= turbo_frame_tag :language_model_test do %>
<% if @answer %> -
Tested <%= @answer %>
+
Result: <%= @answer %>
<% else %> -
Failed
+
<% end %>
<% end %> From 47a6093a9cef88b8966bb6f07fc2ca64bc7a9a9b Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Thu, 12 Dec 2024 15:38:17 -0500 Subject: [PATCH 05/14] Use turbo stream and fix for new form --- .../settings/language_models_controller.rb | 7 ++++++- app/models/language_model.rb | 4 ++-- app/services/ai_backend/anthropic.rb | 2 +- app/services/ai_backend/open_ai.rb | 6 ++++-- app/views/settings/language_models/_form.html.erb | 13 ++++++++----- app/views/settings/language_models/test.html.erb | 9 --------- .../settings/language_models/test.turbo_stream.erb | 11 +++++++++++ 7 files changed, 32 insertions(+), 20 deletions(-) delete mode 100644 app/views/settings/language_models/test.html.erb create mode 100644 app/views/settings/language_models/test.turbo_stream.erb diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index 0beaa7e8..0d730760 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -36,7 +36,12 @@ def update def test @language_model = Current.user.language_models.find_by(id: params[:language_model_id]) - @answer = @language_model.test + @answer = @language_model.test(params[:api_name]) + + respond_to do |format| + format.html { redirect_to settings_language_models_path, notice: "Tested", status: :see_other } + format.turbo_stream + end end def destroy diff --git a/app/models/language_model.rb b/app/models/language_model.rb index a1335842..ffd44bb0 100644 --- a/app/models/language_model.rb +++ b/app/models/language_model.rb @@ -31,8 +31,8 @@ def supports_tools? api_service.name != "Groq" # TODO: Remove this short circuit once I can debug tool use with Groq end - def test - ai_backend.test_language_model(self) + def test(api_name = nil) + ai_backend.test_language_model(self, api_name) end private diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index 7a0bcaf1..3e2da834 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -25,7 +25,7 @@ def initialize(user, assistant, conversation = nil, message = nil) end end - def self.test_language_model(language_model) + def self.test_language_model(language_model, api_name = nil) client = ::Anthropic::Client.new( uri_base: language_model.api_service.url, access_token: language_model.api_service.effective_token diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index 1f36c56b..4d38a2c1 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -25,14 +25,16 @@ def initialize(user, assistant, conversation = nil, message = nil) end end - def self.test_language_model(language_model) + def self.test_language_model(language_model, api_name = nil) + api_name ||= language_model.api_name + client = ::OpenAI::Client.new( access_token: language_model.api_service.effective_token, uri_base: language_model.api_service.url ) client.chat(parameters: { - model: language_model.api_name, + model: api_name, messages: [{ role: "user", content: "Hello!" }], }).dig("choices", 0, "message", "content") diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 8f8905dc..0c5dde12 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -18,10 +18,12 @@
<%= form.label :api_name %> - <%= turbo_frame_tag :language_model_test, class: "inline-block" do %> - <%= link_to "Test", settings_language_model_test_path(@language_model), class: "inline-block ml-5 py-3" %> - <%= render template: "settings/language_models/test" %> - <% end %> +
+ <% if language_model.persisted? %> + <%= link_url = settings_language_models_path + "/" + language_model.id.to_s + "/test" %> + <%= link_to "Test", link_url, data: { turbo_stream: true }, class: "inline-block ml-5 py-3" %> + <% end %> +
<%= form.text_field :api_name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> As specified in the API docs
@@ -61,6 +63,7 @@ <%= form.check_box :supports_system_message %> <%= form.label :supports_system_message, "Supports System Message (Instructions)?" %> + <%= form.submit "Save", class: %| inline-block font-bold @@ -71,4 +74,4 @@ |, data: { turbo_submits_with: "Saving..." } %> -<% end%> +<% end %> diff --git a/app/views/settings/language_models/test.html.erb b/app/views/settings/language_models/test.html.erb deleted file mode 100644 index 4fba821f..00000000 --- a/app/views/settings/language_models/test.html.erb +++ /dev/null @@ -1,9 +0,0 @@ - <%= turbo_frame_tag :language_model_test do %> -
- <% if @answer %> -
Result: <%= @answer %>
- <% else %> -
- <% end %> -
- <% end %> diff --git a/app/views/settings/language_models/test.turbo_stream.erb b/app/views/settings/language_models/test.turbo_stream.erb new file mode 100644 index 00000000..529ebdba --- /dev/null +++ b/app/views/settings/language_models/test.turbo_stream.erb @@ -0,0 +1,11 @@ + + + From 7701f0e6b95ada8a2d91bf5f0aaa0c1f77ac9907 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Fri, 13 Dec 2024 06:26:23 -0500 Subject: [PATCH 06/14] Fix view and start adding update_url --- app/controllers/settings/language_models_controller.rb | 6 ++++-- .../stimulus/language_model_test_controller.js | 10 ++++++++++ app/views/settings/language_models/_form.html.erb | 10 +++++----- 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 app/javascript/stimulus/language_model_test_controller.js diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index 0d730760..b024efeb 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -35,11 +35,13 @@ def update end def test + Rails.logger.info("TESTING LANGUAGE MODEL: #{params}") + Rails.logger.info("URL: #{request.fullpath}") @language_model = Current.user.language_models.find_by(id: params[:language_model_id]) - @answer = @language_model.test(params[:api_name]) + @answer = @language_model.test(params[:query]) respond_to do |format| - format.html { redirect_to settings_language_models_path, notice: "Tested", status: :see_other } + format.html { redirect_to settings_language_models_path, notice: "Tested: #{@answer}", status: :see_other } format.turbo_stream end end diff --git a/app/javascript/stimulus/language_model_test_controller.js b/app/javascript/stimulus/language_model_test_controller.js new file mode 100644 index 00000000..b77a3786 --- /dev/null +++ b/app/javascript/stimulus/language_model_test_controller.js @@ -0,0 +1,10 @@ +import { Controller } from "@hotwired/stimulus" +static targets = ["input"] + +// Connects to data-controller="language-model" +export default class extends Controller { + update_link(event) { + const link = document.getElementById("test_language_model") + link.href = link.href + "?query=" + event.target.value + } +} diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 0c5dde12..a1b2cc72 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -16,15 +16,15 @@ <%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> -
+
<%= form.label :api_name %> -
+
<% if language_model.persisted? %> - <%= link_url = settings_language_models_path + "/" + language_model.id.to_s + "/test" %> - <%= link_to "Test", link_url, data: { turbo_stream: true }, class: "inline-block ml-5 py-3" %> + <% link_url = settings_language_models_path + "/" + language_model.id.to_s + "/test" %> + <%= link_to "(Test)", link_url, id: "test_language_model", data: { turbo_stream: true, action: "click->test-language-model#update_link" }, class: "inline-block ml-5" %> <% end %>
- <%= form.text_field :api_name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> + <%= form.text_field :api_name, data-test-language-model-target: "input", class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> As specified in the API docs
From 26799e38d902d90bdbc96ea4e9a466145c496102 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Fri, 13 Dec 2024 08:05:40 -0500 Subject: [PATCH 07/14] Fix stimulus target --- app/views/settings/language_models/_form.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index a1b2cc72..31621614 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -24,7 +24,7 @@ <%= link_to "(Test)", link_url, id: "test_language_model", data: { turbo_stream: true, action: "click->test-language-model#update_link" }, class: "inline-block ml-5" %> <% end %>
- <%= form.text_field :api_name, data-test-language-model-target: "input", class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> + <%= form.text_field :api_name, data: { test_language_model_target: "input" }, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> As specified in the API docs
From 89123d1bf11b1c0f93019434c7fe6f2b7c7fbc3a Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Fri, 13 Dec 2024 09:26:39 -0500 Subject: [PATCH 08/14] Cleanup. Still WIP. --- app/services/ai_backend/anthropic.rb | 29 +++++++++++++--------------- app/services/ai_backend/gemini.rb | 29 ++++++++++++++++++++++++---- app/services/ai_backend/open_ai.rb | 22 ++++++++++----------- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index 3e2da834..49113fbf 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -14,34 +14,31 @@ def self.client end end - def initialize(user, assistant, conversation = nil, message = nil) - super(user, assistant, conversation, message) - begin - raise ::Anthropic::ConfigurationError if assistant.api_service.requires_token? && assistant.api_service.effective_token.blank? - Rails.logger.info "Connecting to Anthropic API server at #{assistant.api_service.url} with access token of length #{assistant.api_service.effective_token.to_s.length}" - @client = self.class.client.new(uri_base: assistant.api_service.url, access_token: assistant.api_service.effective_token) - rescue ::Faraday::UnauthorizedError => e - raise ::Anthropic::ConfigurationError - end - end - def self.test_language_model(language_model, api_name = nil) client = ::Anthropic::Client.new( uri_base: language_model.api_service.url, access_token: language_model.api_service.effective_token ) - # TODO: Implement this. Use get_oneoff_message? - # client.chat(parameters: { - # model: language_model.api_name, - # messages: [{ role: "user", content: "Hello!" }], - # }).dig("choices", 0, "message", "content") + # TODO: Implement this. Send: messages: [{ role: "user", content: "Hello!" }] + # and return the first message content. "Testing Not Implemented Yet" rescue ::Faraday::Error => e e.message end + def initialize(user, assistant, conversation = nil, message = nil) + super(user, assistant, conversation, message) + begin + raise ::Anthropic::ConfigurationError if assistant.api_service.requires_token? && assistant.api_service.effective_token.blank? + Rails.logger.info "Connecting to Anthropic API server at #{assistant.api_service.url} with access token of length #{assistant.api_service.effective_token.to_s.length}" + @client = self.class.client.new(uri_base: assistant.api_service.url, access_token: assistant.api_service.effective_token) + rescue ::Faraday::UnauthorizedError => e + raise ::Anthropic::ConfigurationError + end + end + private def client_method_name diff --git a/app/services/ai_backend/gemini.rb b/app/services/ai_backend/gemini.rb index e9ef49ae..7072be9b 100644 --- a/app/services/ai_backend/gemini.rb +++ b/app/services/ai_backend/gemini.rb @@ -15,6 +15,31 @@ def self.client end end + def self.test_language_model(language_model, api_name = nil) + api_name ||= language_model.api_name + + client = ::Gemini.new( + credentials: { + service: "generative-language-api", + api_key: language_model.api_service.effective_token, + version: "v1beta" + }, + options: { + model: api_name, + server_sent_events: true + } + ) + + # TODO: Fix this. Response is 400 currently. + # response = client.generate_content({ + # system_instruction: "Hello!", + # contents: { role: "user", parts: { text: "Hello!" }} + # }) + # response.dig("candidates", 0, "content", "parts", 0, "text") + + "Testing Not Implemented Yet" + end + def initialize(user, assistant, conversation = nil, message = nil) super(user, assistant, conversation, message) begin @@ -87,10 +112,6 @@ def stream_next_conversation_message(&chunk_handler) return nil end - def self.test_language_model(language_model) - "Testing Not Implemented Yet" - end - private def system_message(content) diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index 4d38a2c1..0d773046 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -14,17 +14,6 @@ def self.client end end - def initialize(user, assistant, conversation = nil, message = nil) - super(user, assistant, conversation, message) - begin - raise ::OpenAI::ConfigurationError if assistant.api_service.requires_token? && assistant.api_service.effective_token.blank? - Rails.logger.info "Connecting to OpenAI API server at #{assistant.api_service.url} with access token of length #{assistant.api_service.effective_token.to_s.length}" - @client = self.class.client.new(uri_base: assistant.api_service.url, access_token: assistant.api_service.effective_token) - rescue ::Faraday::UnauthorizedError => e - raise ::OpenAI::ConfigurationError - end - end - def self.test_language_model(language_model, api_name = nil) api_name ||= language_model.api_name @@ -42,6 +31,17 @@ def self.test_language_model(language_model, api_name = nil) e.message end + def initialize(user, assistant, conversation = nil, message = nil) + super(user, assistant, conversation, message) + begin + raise ::OpenAI::ConfigurationError if assistant.api_service.requires_token? && assistant.api_service.effective_token.blank? + Rails.logger.info "Connecting to OpenAI API server at #{assistant.api_service.url} with access token of length #{assistant.api_service.effective_token.to_s.length}" + @client = self.class.client.new(uri_base: assistant.api_service.url, access_token: assistant.api_service.effective_token) + rescue ::Faraday::UnauthorizedError => e + raise ::OpenAI::ConfigurationError + end + end + private def client_method_name From d6c765ba4fdd09d49c285a2c44e2b4e1e4cbe467 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Fri, 13 Dec 2024 12:54:09 -0500 Subject: [PATCH 09/14] Fix error message. Still WIP. --- .../stimulus/language_model_test_controller.js | 10 ---------- app/javascript/stimulus/testing_controller.js | 10 ++++++++++ app/services/ai_backend/open_ai.rb | 2 +- app/views/settings/language_models/_form.html.erb | 13 ++++++++++--- .../language_models/test.turbo_stream.erb | 15 ++++++++++----- 5 files changed, 31 insertions(+), 19 deletions(-) delete mode 100644 app/javascript/stimulus/language_model_test_controller.js create mode 100644 app/javascript/stimulus/testing_controller.js diff --git a/app/javascript/stimulus/language_model_test_controller.js b/app/javascript/stimulus/language_model_test_controller.js deleted file mode 100644 index b77a3786..00000000 --- a/app/javascript/stimulus/language_model_test_controller.js +++ /dev/null @@ -1,10 +0,0 @@ -import { Controller } from "@hotwired/stimulus" -static targets = ["input"] - -// Connects to data-controller="language-model" -export default class extends Controller { - update_link(event) { - const link = document.getElementById("test_language_model") - link.href = link.href + "?query=" + event.target.value - } -} diff --git a/app/javascript/stimulus/testing_controller.js b/app/javascript/stimulus/testing_controller.js new file mode 100644 index 00000000..dce3a5d4 --- /dev/null +++ b/app/javascript/stimulus/testing_controller.js @@ -0,0 +1,10 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["input"] + + update_link(event) { + const link = event.currentTarget; + link.href = link.href + "?query=" + this.inputTarget.value + } +} diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index 0d773046..1e8c5d82 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -28,7 +28,7 @@ def self.test_language_model(language_model, api_name = nil) }).dig("choices", 0, "message", "content") rescue ::Faraday::Error => e - e.message + "Error: #{e.message}" end def initialize(user, assistant, conversation = nil, message = nil) diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 31621614..8bdea97e 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -16,15 +16,22 @@ <%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> -
+
<%= form.label :api_name %>
<% if language_model.persisted? %> <% link_url = settings_language_models_path + "/" + language_model.id.to_s + "/test" %> - <%= link_to "(Test)", link_url, id: "test_language_model", data: { turbo_stream: true, action: "click->test-language-model#update_link" }, class: "inline-block ml-5" %> + <%= link_to "(Test)", link_url, + id: "test_result", + data: { turbo_stream: true, action: "click->testing#update_link" }, + class: "inline-block ml-5" + %> <% end %>
- <%= form.text_field :api_name, data: { test_language_model_target: "input" }, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> + <%= form.text_field :api_name, + data: { testing_target: "input" }, + class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" + %> As specified in the API docs
diff --git a/app/views/settings/language_models/test.turbo_stream.erb b/app/views/settings/language_models/test.turbo_stream.erb index 529ebdba..114ac859 100644 --- a/app/views/settings/language_models/test.turbo_stream.erb +++ b/app/views/settings/language_models/test.turbo_stream.erb @@ -1,11 +1,16 @@ - + From f02d7669913f85d390313f549a26afe56f9bafe1 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Fri, 13 Dec 2024 17:04:55 -0500 Subject: [PATCH 10/14] Cleanup. Still WIP. --- app/views/settings/language_models/_form.html.erb | 8 ++++---- .../language_models/test.turbo_stream.erb | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 8bdea97e..b7f4debb 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -16,18 +16,18 @@ <%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %>
-
+
<%= form.label :api_name %> -
+ <% if language_model.persisted? %> <% link_url = settings_language_models_path + "/" + language_model.id.to_s + "/test" %> <%= link_to "(Test)", link_url, id: "test_result", data: { turbo_stream: true, action: "click->testing#update_link" }, - class: "inline-block ml-5" + class: "underline text-blue-600" %> <% end %> -
+ <%= form.text_field :api_name, data: { testing_target: "input" }, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" diff --git a/app/views/settings/language_models/test.turbo_stream.erb b/app/views/settings/language_models/test.turbo_stream.erb index 114ac859..ce79b122 100644 --- a/app/views/settings/language_models/test.turbo_stream.erb +++ b/app/views/settings/language_models/test.turbo_stream.erb @@ -1,16 +1,19 @@ From 5e5b774253a4cbd0088cfa78c928f7ee4b03486c Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Fri, 13 Dec 2024 17:53:07 -0500 Subject: [PATCH 11/14] Implement for anthropic and gemini --- .../settings/language_models_controller.rb | 2 -- app/services/ai_backend.rb | 1 - app/services/ai_backend/anthropic.rb | 15 +++++++++++---- app/services/ai_backend/gemini.rb | 14 ++++++-------- app/views/settings/language_models/_form.html.erb | 4 ++-- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index b024efeb..abe323b7 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -35,8 +35,6 @@ def update end def test - Rails.logger.info("TESTING LANGUAGE MODEL: #{params}") - Rails.logger.info("URL: #{request.fullpath}") @language_model = Current.user.language_models.find_by(id: params[:language_model_id]) @answer = @language_model.test(params[:query]) diff --git a/app/services/ai_backend.rb b/app/services/ai_backend.rb index f92142da..d4204f08 100644 --- a/app/services/ai_backend.rb +++ b/app/services/ai_backend.rb @@ -2,7 +2,6 @@ class AIBackend include Utilities, Tools attr :client - attr :test_language_model def initialize(user, assistant, conversation = nil, message = nil) @user = user diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index 49113fbf..43e669c6 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -15,16 +15,23 @@ def self.client end def self.test_language_model(language_model, api_name = nil) + api_name ||= language_model.api_name + client = ::Anthropic::Client.new( uri_base: language_model.api_service.url, access_token: language_model.api_service.effective_token ) - # TODO: Implement this. Send: messages: [{ role: "user", content: "Hello!" }] - # and return the first message content. + response = client.messages( + model: api_name, + messages: [ + { "role": "user", "content": "Hello!" } + ], + system: "You are a helpful assistant.", + parameters: { max_tokens: 1000 } + ).dig("content", 0, "text") - "Testing Not Implemented Yet" - rescue ::Faraday::Error => e + rescue => e e.message end diff --git a/app/services/ai_backend/gemini.rb b/app/services/ai_backend/gemini.rb index 7072be9b..069d42d4 100644 --- a/app/services/ai_backend/gemini.rb +++ b/app/services/ai_backend/gemini.rb @@ -30,14 +30,12 @@ def self.test_language_model(language_model, api_name = nil) } ) - # TODO: Fix this. Response is 400 currently. - # response = client.generate_content({ - # system_instruction: "Hello!", - # contents: { role: "user", parts: { text: "Hello!" }} - # }) - # response.dig("candidates", 0, "content", "parts", 0, "text") - - "Testing Not Implemented Yet" + client.generate_content({ + contents: { role: "user", parts: { text: "Hello!" }} + }).dig("candidates", 0, "content", "parts", 0, "text") + + rescue ::Faraday::Error => e + "Error: #{e.message}" end def initialize(user, assistant, conversation = nil, message = nil) diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index b7f4debb..4e19845f 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -16,7 +16,7 @@ <%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %>
-
+
<%= form.label :api_name %> <% if language_model.persisted? %> @@ -31,7 +31,7 @@ <%= form.text_field :api_name, data: { testing_target: "input" }, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" - %> + %> As specified in the API docs
From 6b1cbad278c2dde601c42158f67fbb698eb8f21c Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Sat, 14 Dec 2024 08:04:24 -0500 Subject: [PATCH 12/14] Add controller test --- .../settings/language_models_controller.rb | 2 +- app/javascript/stimulus/testing_controller.js | 2 +- app/services/ai_backend/anthropic.rb | 2 +- app/services/ai_backend/open_ai.rb | 25 +++++++++++++------ .../language_models_controller_test.rb | 8 ++++++ 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index abe323b7..70f6d3bf 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -36,7 +36,7 @@ def update def test @language_model = Current.user.language_models.find_by(id: params[:language_model_id]) - @answer = @language_model.test(params[:query]) + @answer = @language_model.test(params[:model]) respond_to do |format| format.html { redirect_to settings_language_models_path, notice: "Tested: #{@answer}", status: :see_other } diff --git a/app/javascript/stimulus/testing_controller.js b/app/javascript/stimulus/testing_controller.js index dce3a5d4..78b455a5 100644 --- a/app/javascript/stimulus/testing_controller.js +++ b/app/javascript/stimulus/testing_controller.js @@ -5,6 +5,6 @@ export default class extends Controller { update_link(event) { const link = event.currentTarget; - link.href = link.href + "?query=" + this.inputTarget.value + link.href = link.href + "?model=" + this.inputTarget.value } } diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index 43e669c6..d1a5680b 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -32,7 +32,7 @@ def self.test_language_model(language_model, api_name = nil) ).dig("content", 0, "text") rescue => e - e.message + "Error: #{e.message}" end def initialize(user, assistant, conversation = nil, message = nil) diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index 1e8c5d82..b7d87bda 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -16,17 +16,26 @@ def self.client def self.test_language_model(language_model, api_name = nil) api_name ||= language_model.api_name - - client = ::OpenAI::Client.new( - access_token: language_model.api_service.effective_token, - uri_base: language_model.api_service.url - ) - - client.chat(parameters: { + params = { model: api_name, messages: [{ role: "user", content: "Hello!" }], - }).dig("choices", 0, "message", "content") + } + + if Rails.env.test? + client = ::TestClient::OpenAI.new( + access_token: language_model.api_service.effective_token, + uri_base: language_model.api_service.url + ) + response = client.send(:chat, ** {parameters: params}) + else + client = ::OpenAI::Client.new( + access_token: language_model.api_service.effective_token, + uri_base: language_model.api_service.url + ) + response = client.chat(parameters: params) + end + response.dig("choices", 0, "message", "content") rescue ::Faraday::Error => e "Error: #{e.message}" end diff --git a/test/controllers/settings/language_models_controller_test.rb b/test/controllers/settings/language_models_controller_test.rb index 1accfe13..f35b42a5 100644 --- a/test/controllers/settings/language_models_controller_test.rb +++ b/test/controllers/settings/language_models_controller_test.rb @@ -199,4 +199,12 @@ class Settings::LanguageModelsControllerTest < ActionDispatch::IntegrationTest assert_select 'input[name="language_model[supports_system_message]"][checked="checked"]', false end end + + test "test should return success and a message" do + TestClient::OpenAI.stub :text, "Success." do + get settings_language_model_test_url(format: :turbo_stream, language_model_id: language_models(:guanaco).id, model: "gpt-4o") + assert_response :success + assert_contains_text "div#test_result", "Success." + end + end end From 37fae04a7cc66b6ed7b6d9b19b39d5d6b254126c Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Mon, 23 Dec 2024 09:25:17 -0500 Subject: [PATCH 13/14] Add api test and anthropic and gemeni --- .../settings/api_services_controller.rb | 10 ++++++ app/javascript/stimulus/testing_controller.js | 21 +++++++++++-- app/models/api_service.rb | 4 +++ app/services/ai_backend.rb | 21 +++++++++++++ app/services/ai_backend/anthropic.rb | 13 ++++---- app/services/ai_backend/gemini.rb | 8 ++--- app/services/ai_backend/open_ai.rb | 23 ++++++-------- .../settings/api_services/_form.html.erb | 31 ++++++++++++++++--- .../api_services/test.turbo_stream.erb | 11 +++++++ .../settings/language_models/_form.html.erb | 13 ++++---- .../language_models/test.turbo_stream.erb | 10 +----- config/routes.rb | 4 ++- 12 files changed, 121 insertions(+), 48 deletions(-) create mode 100644 app/views/settings/api_services/test.turbo_stream.erb diff --git a/app/controllers/settings/api_services_controller.rb b/app/controllers/settings/api_services_controller.rb index ce6a3831..5ac8251a 100644 --- a/app/controllers/settings/api_services_controller.rb +++ b/app/controllers/settings/api_services_controller.rb @@ -30,6 +30,16 @@ def update end end + def test + @api_service = Current.user.api_services.find_by(id: params[:api_service_id]) + @answer = @api_service.test_api_service(params[:url], params[:token]) + + respond_to do |format| + format.html { redirect_to settings_api_services_path, notice: "Tested: #{@answer}", status: :see_other } + format.turbo_stream + end + end + def destroy @api_service.deleted! redirect_to settings_api_services_path, notice: "Deleted", status: :see_other diff --git a/app/javascript/stimulus/testing_controller.js b/app/javascript/stimulus/testing_controller.js index 78b455a5..c9fc27de 100644 --- a/app/javascript/stimulus/testing_controller.js +++ b/app/javascript/stimulus/testing_controller.js @@ -1,10 +1,25 @@ import { Controller } from "@hotwired/stimulus" export default class extends Controller { - static targets = ["input"] + static targets = ["model", "test", "url","token"] - update_link(event) { + update_link_language_model(event) { const link = event.currentTarget; - link.href = link.href + "?model=" + this.inputTarget.value + const href = link.href.split('?')[0]; + link.href = href + "?model=" + this.modelTarget.value + } + + update_link_api_service(event) { + const link = event.currentTarget; + const href = link.href.split('?')[0]; + link.href = href + "?url=" + this.urlTarget.value + "&token=" + this.tokenTarget.value + console.log("Link: ", link) + } + + disable_test_link() { + const link = this.testTarget; + link.addEventListener('click', function(event) { + event.preventDefault(); + }); } } diff --git a/app/models/api_service.rb b/app/models/api_service.rb index 9ad738fd..17798d05 100644 --- a/app/models/api_service.rb +++ b/app/models/api_service.rb @@ -39,6 +39,10 @@ def effective_token token.presence || default_llm_key end + def test_api_service(url = nil, token = nil) + ai_backend.test_api_service(self, url, token) + end + private def default_llm_key diff --git a/app/services/ai_backend.rb b/app/services/ai_backend.rb index d4204f08..5f14342b 100644 --- a/app/services/ai_backend.rb +++ b/app/services/ai_backend.rb @@ -48,6 +48,27 @@ def stream_next_conversation_message(&chunk_handler) end end + def self.test_language_model(language_model, api_name = nil) + api_name ||= language_model.api_name + url = language_model.api_service.url + token = language_model.api_service.effective_token + return "Error: API key (token) is blank" if language_model.api_service.requires_token? && token.blank? + + test_execute(url, token, api_name) + end + + def self.test_api_service(api_service, url = nil, token = nil) + url ||= api_service.url + token ||= api_service.effective_token + language_model = LanguageModel.where(best: true, api_service: api_service).first + api_name = language_model.api_name unless language_model.nil? + + return "Error: API key (token) is blank" if api_service.requires_token? && token.blank? + return "Error: API name is blank. Define a best Language Model for this API service." if api_name.blank? + + test_execute(url, token, api_name) + end + private def client_method_name diff --git a/app/services/ai_backend/anthropic.rb b/app/services/ai_backend/anthropic.rb index d1a5680b..638df9ea 100644 --- a/app/services/ai_backend/anthropic.rb +++ b/app/services/ai_backend/anthropic.rb @@ -14,15 +14,15 @@ def self.client end end - def self.test_language_model(language_model, api_name = nil) - api_name ||= language_model.api_name - + def self.test_execute(url, token, api_name) + Rails.logger.info "Connecting to Anthropic API server at #{url} with access token of length #{token.to_s.length}" client = ::Anthropic::Client.new( - uri_base: language_model.api_service.url, - access_token: language_model.api_service.effective_token + uri_base: url, + access_token: token ) - response = client.messages( + Rails.logger.info "Testing using model #{api_name}" + client.messages( model: api_name, messages: [ { "role": "user", "content": "Hello!" } @@ -30,7 +30,6 @@ def self.test_language_model(language_model, api_name = nil) system: "You are a helpful assistant.", parameters: { max_tokens: 1000 } ).dig("content", 0, "text") - rescue => e "Error: #{e.message}" end diff --git a/app/services/ai_backend/gemini.rb b/app/services/ai_backend/gemini.rb index 069d42d4..d125fc68 100644 --- a/app/services/ai_backend/gemini.rb +++ b/app/services/ai_backend/gemini.rb @@ -15,13 +15,12 @@ def self.client end end - def self.test_language_model(language_model, api_name = nil) - api_name ||= language_model.api_name - + def self.test_execute(url, token, api_name) + Rails.logger.info "Connecting to Gemini API server at #{url} with access token of length #{token.to_s.length}" client = ::Gemini.new( credentials: { service: "generative-language-api", - api_key: language_model.api_service.effective_token, + api_key: token, version: "v1beta" }, options: { @@ -33,7 +32,6 @@ def self.test_language_model(language_model, api_name = nil) client.generate_content({ contents: { role: "user", parts: { text: "Hello!" }} }).dig("candidates", 0, "content", "parts", 0, "text") - rescue ::Faraday::Error => e "Error: #{e.message}" end diff --git a/app/services/ai_backend/open_ai.rb b/app/services/ai_backend/open_ai.rb index b7d87bda..f40c730f 100644 --- a/app/services/ai_backend/open_ai.rb +++ b/app/services/ai_backend/open_ai.rb @@ -14,25 +14,22 @@ def self.client end end - def self.test_language_model(language_model, api_name = nil) - api_name ||= language_model.api_name - params = { - model: api_name, - messages: [{ role: "user", content: "Hello!" }], - } - + def self.test_execute(url, token, api_name) if Rails.env.test? client = ::TestClient::OpenAI.new( - access_token: language_model.api_service.effective_token, - uri_base: language_model.api_service.url + access_token: token, + uri_base: url ) - response = client.send(:chat, ** {parameters: params}) + response = client.send(:chat, ** {parameters: {model: api_name, messages: [{ role: "user", content: "Hello!" }]}}) else + Rails.logger.info "Connecting to OpenAI API server at #{url} with access token of length #{token.to_s.length}" client = ::OpenAI::Client.new( - access_token: language_model.api_service.effective_token, - uri_base: language_model.api_service.url + access_token: token, + uri_base: url ) - response = client.chat(parameters: params) + + Rails.logger.info "Testing using model #{api_name}" + response = client.chat(parameters: {model: api_name, messages: [{ role: "user", content: "Hello!" }]}) end response.dig("choices", 0, "message", "content") diff --git a/app/views/settings/api_services/_form.html.erb b/app/views/settings/api_services/_form.html.erb index a6c9d073..30e5e8b9 100644 --- a/app/views/settings/api_services/_form.html.erb +++ b/app/views/settings/api_services/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_with(model: [:settings, api_service], class: "contents") do |form| %> +<%= form_with(model: [:settings, api_service], class: "contents", data: {controller: "testing"}) do |form| %> <% if api_service.errors.any? %>

<%= pluralize(api_service.errors.count, "error") %> prohibited this API service from being saved:

@@ -21,6 +21,7 @@ <%= form.select :driver, APIService.drivers.keys, {}, + data: { action: "change->testing#disable_test_link" }, class: %| block border border-gray-200 outline-none @@ -32,9 +33,22 @@ %>
-
+
<%= form.label :url %> - <%= form.text_field :url, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> + + <% if api_service.persisted? %> + <% link_url = settings_api_services_path + "/" + api_service.id.to_s + "/test" %> + <%= link_to "Test", link_url, + data: { testing_target: "test", turbo_stream: true, action: "click->testing#update_link_api_service" }, + class: "underline text-blue-600" + %> + <% end %> + + + <%= form.text_field :url, + data: { testing_target: "url" }, + class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" + %>
@@ -167,7 +181,16 @@ %>. - <%= form.text_field :token, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black", autocomplete: "off" %> + <%= form.text_field :token, + class: %| + block shadow + rounded-md border border-gray-200 outline-none + px-3 py-2 mt-2 w-full dark:text-black + |, + autocomplete: "off", + id: "input_token", + data: { testing_target: "token" } + %>
<%= form.submit "Save", diff --git a/app/views/settings/api_services/test.turbo_stream.erb b/app/views/settings/api_services/test.turbo_stream.erb new file mode 100644 index 00000000..14155ff6 --- /dev/null +++ b/app/views/settings/api_services/test.turbo_stream.erb @@ -0,0 +1,11 @@ + + + diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 4e19845f..934961a7 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_with(model: [:settings, language_model], class: "contents") do |form| %> +<%= form_with(model: [:settings, language_model], class: "contents", data: { controller: "testing" }) do |form| %> <% if language_model.errors.any? %>

<%= pluralize(language_model.errors.count, "error") %> prohibited this language model from being saved:

@@ -16,20 +16,20 @@ <%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %>
-
+
<%= form.label :api_name %> <% if language_model.persisted? %> <% link_url = settings_language_models_path + "/" + language_model.id.to_s + "/test" %> - <%= link_to "(Test)", link_url, - id: "test_result", - data: { turbo_stream: true, action: "click->testing#update_link" }, + <%= link_to "Test", link_url, + data: { testing_target: "test", turbo_stream: true, action: "click->testing#update_link_language_model" }, class: "underline text-blue-600" %> + <% end %> <%= form.text_field :api_name, - data: { testing_target: "input" }, + data: { testing_target: "model" }, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full dark:text-black" %> As specified in the API docs @@ -41,6 +41,7 @@ <%= form.select :api_service_id, Current.user.api_services.ordered.pluck(:name, :id).reverse, {}, + data: { action: "change->testing#disable_test_link" }, class: %| block border border-gray-200 outline-none diff --git a/app/views/settings/language_models/test.turbo_stream.erb b/app/views/settings/language_models/test.turbo_stream.erb index ce79b122..14155ff6 100644 --- a/app/views/settings/language_models/test.turbo_stream.erb +++ b/app/views/settings/language_models/test.turbo_stream.erb @@ -1,18 +1,10 @@ diff --git a/config/routes.rb b/config/routes.rb index 17a08926..5f5a2fb3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,7 +19,9 @@ resources :language_models do get :test, to: "language_models#test" end - resources :api_services, except: [:show] + resources :api_services, except: [:show] do + get :test, to: "api_services#test" + end resources :memories, only: [:index, :destroy] do delete :destroy, to: "memories#destroy_all", on: :collection end From 7841dafea25a30f04d8aed04b03802ec7303f903 Mon Sep 17 00:00:00 2001 From: Matt Lindsey Date: Mon, 23 Dec 2024 15:27:26 -0500 Subject: [PATCH 14/14] Add test for api service test controller --- test/controllers/settings/api_services_controller_test.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/controllers/settings/api_services_controller_test.rb b/test/controllers/settings/api_services_controller_test.rb index 2e42e25f..7bb44c58 100644 --- a/test/controllers/settings/api_services_controller_test.rb +++ b/test/controllers/settings/api_services_controller_test.rb @@ -108,4 +108,12 @@ class Settings::APIServicesControllerTest < ActionDispatch::IntegrationTest get edit_settings_api_service_url(api_services(:keith_other_service)) assert_select "button#instructions.hidden" end + + test "test should return success and a message" do + TestClient::OpenAI.stub :text, "Success." do + get settings_api_service_test_url(format: :turbo_stream, api_service_id: api_services(:keith_openai_service).id, url: "https://api.openai.com/v1", token: "abc-secret123") + assert_response :success + assert_contains_text "div#test_result", "Success." + end + end end