diff --git a/app/controllers/settings/language_models_controller.rb b/app/controllers/settings/language_models_controller.rb index 7dde2fdd..5e0af71d 100644 --- a/app/controllers/settings/language_models_controller.rb +++ b/app/controllers/settings/language_models_controller.rb @@ -63,6 +63,6 @@ def set_system_language_model end def language_model_params - params.require(:language_model).permit(:api_name, :name, :best, :supports_images, :supports_tools, :api_service_id, :supports_system_message, :supports_pdf) + params.require(:language_model).permit(:api_name, :name, :supports_images, :supports_tools, :api_service_id, :supports_system_message, :supports_pdf) end end diff --git a/app/models/language_model.rb b/app/models/language_model.rb index ffd44bb0..b9b8e539 100644 --- a/app/models/language_model.rb +++ b/app/models/language_model.rb @@ -13,11 +13,9 @@ class LanguageModel < ApplicationRecord validates :api_name, :name, :position, presence: true before_save :soft_delete_assistants, if: -> { has_attribute?(:deleted_at) && deleted_at && deleted_at_changed? && deleted_at_was.nil? } - after_save :update_best_language_model_for_api_service - scope :ordered, -> { order(Arel.sql("CASE WHEN best THEN 0 ELSE position END")).order(:position) } + scope :ordered, -> { order(:position) } scope :for_user, ->(user) { where(user_id: user.id).not_deleted } - scope :best_for_api_service, ->(api_service) { where(best: true, api_service: api_service) } delegate :ai_backend, to: :api_service delegate :name, to: :api_service, prefix: true, allow_nil: true @@ -45,11 +43,4 @@ def soft_delete_assistants assistants.update_all(deleted_at: Time.current) end - # Only one best language model per API service - def update_best_language_model_for_api_service - if best? - api_service.language_models.update_all(best: false) - update_column(:best, true) - end - end end diff --git a/app/models/language_model/export.rb b/app/models/language_model/export.rb index ee019076..843240a3 100644 --- a/app/models/language_model/export.rb +++ b/app/models/language_model/export.rb @@ -4,7 +4,6 @@ module LanguageModel::Export DEFAULT_EXPORT_ONLY = %i[ api_name name - best api_service_name supports_images supports_tools diff --git a/app/services/ai_backend.rb b/app/services/ai_backend.rb index 5f14342b..48a7c2f0 100644 --- a/app/services/ai_backend.rb +++ b/app/services/ai_backend.rb @@ -60,11 +60,11 @@ def self.test_language_model(language_model, api_name = nil) 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 + language_model = api_service.language_models.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? + return "Error: API name is blank. Define a Language Model for this API service." if api_name.blank? test_execute(url, token, api_name) end diff --git a/app/views/settings/language_models/_form.html.erb b/app/views/settings/language_models/_form.html.erb index 584c4f1c..b14e1502 100644 --- a/app/views/settings/language_models/_form.html.erb +++ b/app/views/settings/language_models/_form.html.erb @@ -54,11 +54,6 @@ <% end %> -
- <%= form.check_box :best %> - <%= form.label :best, t('app.settings.language_models.form.best') %> -
-
<%= form.check_box :supports_images %> <%= form.label :supports_images, t('app.settings.language_models.form.supports_images') %> diff --git a/app/views/settings/language_models/index.html.erb b/app/views/settings/language_models/index.html.erb index ba87dae9..b308927c 100644 --- a/app/views/settings/language_models/index.html.erb +++ b/app/views/settings/language_models/index.html.erb @@ -15,7 +15,6 @@ <%= t('app.settings.language_models.table.name') %> - <%= t('app.settings.language_models.table.best') %> <%= t('app.settings.language_models.table.description') %> <%= t('app.settings.language_models.table.api_service') %> <%= t('app.settings.language_models.table.supports_pdf') %> @@ -27,7 +26,6 @@ <%= turbo_frame_tag dom_id(language_model) do %> <%= language_model.api_name %> - <%= language_model.best? ? t('app.generic.yes', default: 'Yes') : t('app.generic.no', default: 'No') %> <%= language_model.name %> <%= n_a_if_blank(language_model.api_service.name) %> <%= language_model.supports_pdf? ? t('app.generic.yes', default: 'Yes') : t('app.generic.no', default: 'No') %> diff --git a/config/locales/de.yml b/config/locales/de.yml index 0df195ad..4b55f4ab 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -61,7 +61,6 @@ de: back: "Zurück" table: name: "API-Name" - best: "Bestes?" description: "Beschreibung" api_service: "API-Dienst" supports_pdf: "Unterstützt PDFs" @@ -70,7 +69,6 @@ de: api_name: "API-Name" api_name_hint: "Wie in der API-Doku angegeben" api_service: "API-Dienst" - best: "Bestes?" supports_images: "Unterstützt Bilder?" supports_tools: "Unterstützt Tools (Function Calling)?" supports_system_message: "Unterstützt Systemnachricht (Anweisungen)?" diff --git a/config/locales/en.yml b/config/locales/en.yml index d985939f..4ad45fce 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -90,7 +90,6 @@ en: back: "Back" table: name: "API Name" - best: "Best?" description: "Description" api_service: "API Service" supports_pdf: "Supports PDFs" @@ -99,7 +98,6 @@ en: api_name: "API Name" api_name_hint: "As specified in the API docs" api_service: "API Service" - best: "Best?" supports_images: "Supports Images?" supports_tools: "Supports Tools (Function Calling)?" supports_system_message: "Supports System Message (Instructions)?" diff --git a/db/migrate/20251020230241_remove_best_from_language_models.rb b/db/migrate/20251020230241_remove_best_from_language_models.rb new file mode 100644 index 00000000..e31d4a43 --- /dev/null +++ b/db/migrate/20251020230241_remove_best_from_language_models.rb @@ -0,0 +1,5 @@ +class RemoveBestFromLanguageModels < ActiveRecord::Migration[8.0] + def change + remove_column :language_models, :best, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index d037d995..483742c7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_09_30_104155) do +ActiveRecord::Schema[8.0].define(version: 2025_10_20_230241) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -172,7 +172,6 @@ t.bigint "user_id", null: false t.bigint "api_service_id" t.boolean "supports_tools", default: false - t.boolean "best", default: false t.boolean "supports_system_message", default: false t.boolean "supports_pdf", default: false, null: false t.index ["api_service_id"], name: "index_language_models_on_api_service_id" diff --git a/models.yml b/models.yml index d7b88387..17da655e 100644 --- a/models.yml +++ b/models.yml @@ -4,251 +4,215 @@ models: name: GPT-5 (latest) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4o name: GPT-4o supports_images: true supports_tools: true - best: true supports_system_message: true api_service_name: OpenAI - api_name: claude-3-5-sonnet-20241022 name: Claude 3.5 Sonnet (latest) supports_images: true supports_tools: true - best: true supports_system_message: true api_service_name: Anthropic - api_name: deepseek-r1-distill-llama-70B name: DeepSeek R1 Distill Llama 70B supports_images: false supports_tools: false - best: true supports_system_message: true api_service_name: Groq - api_name: llama-3.3-70b-versatile name: Llama 3.3 70B Versatile 128k supports_images: false supports_tools: false - best: true supports_system_message: true api_service_name: Groq - api_name: gpt-4o-2024-08-06 name: GPT-4o Omni Multimodal (2024-08-06) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4o-2024-05-13 name: GPT-4o Omni Multimodal (2024-05-13) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo name: GPT-4 Turbo with Vision (latest) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo-2024-04-09 name: GPT-4 Turbo with Vision (2024-04-09) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo-preview name: GPT-4 Turbo Preview supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-0125-preview name: GPT-4 Turbo Preview (2024-01-25) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-1106-preview name: GPT-4 Turbo Preview (2023-11-06) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-vision-preview name: GPT-4 Turbo with Vision Preview (2023-11-06) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-1106-vision-preview name: GPT-4 Turbo with Vision Preview (2023-11-06) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4 name: GPT-4 (latest) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-0613 name: GPT-4 Snapshot improved function calling (2023-06-13) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo name: GPT-3.5 Turbo (latest) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo-0125 name: GPT-3.5 Turbo (2022-01-25) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo-1106 name: GPT-3.5 Turbo (2022-11-06) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: claude-3-5-sonnet-20240620 name: Claude 3.5 Sonnet (2024-06-20) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-3-opus-20240229 name: Claude 3 Opus (2024-02-29) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-3-sonnet-20240229 name: Claude 3 Sonnet (2024-02-29) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-3-haiku-20240307 name: Claude 3 Haiku (2024-03-07) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-2.1 name: Claude 2.1 supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-2.0 name: Claude 2.0 supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-instant-1.2 name: Claude Instant 1.2 supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: llama3-70b-8192 name: Meta Llama 3 70b supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Groq - api_name: llama3-8b-8192 name: Meta Llama 3 8b supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Groq - api_name: mixtral-8x7b-32768 name: Mistral 8 7b supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Groq - api_name: gemma-7b-it name: Google Gemma 7b supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Groq - api_name: gpt-3.5-turbo-instruct name: GPT-3.5 Turbo Instruct supports_images: false supports_tools: false - best: false supports_system_message: false api_service_name: OpenAI - api_name: gpt-3.5-turbo-16k-0613 name: GPT-3.5 Turbo (2022-06-13) supports_images: false supports_tools: false - best: false supports_system_message: false api_service_name: OpenAI - api_name: gpt-4o-mini name: GPT-4o Mini (latest) supports_images: true supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: o1-preview name: OpenAI o1 (preview) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: OpenAI - api_name: claude-3-5-haiku-20241022 name: Claude 3.5 Haiku (latest) supports_images: false supports_tools: true - best: false supports_system_message: true api_service_name: Anthropic - api_name: gemini-1.5-pro-002 name: Google Gemini Pro 1.5 (latest) supports_images: true supports_tools: false - best: true supports_system_message: true api_service_name: Google Gemini diff --git a/test/controllers/settings/language_models_controller_test.rb b/test/controllers/settings/language_models_controller_test.rb index b886abe0..b5bc1dda 100644 --- a/test/controllers/settings/language_models_controller_test.rb +++ b/test/controllers/settings/language_models_controller_test.rb @@ -33,15 +33,14 @@ class Settings::LanguageModelsControllerTest < ActionDispatch::IntegrationTest assert_equal @user, LanguageModel.last.user end - test "create new best language model replaces existing best" do + test "create new language model works" do api_service = api_services(:keith_anthropic_service) - assert_equal api_service.language_models.best.pluck(:api_name), ["claude-best"] + initial_count = api_service.language_models.count params = { api_name: "new-claude-service", api_service_id: api_service.id, - name: "new best service", - best: true, + name: "new service", supports_images: false, supports_tools: false } @@ -51,8 +50,7 @@ class Settings::LanguageModelsControllerTest < ActionDispatch::IntegrationTest end assert_redirected_to settings_language_models_url - - assert_equal api_service.language_models.best.pluck(:api_name), ["new-claude-service"] + assert_equal initial_count + 1, api_service.language_models.count end test "should get edit" do @@ -152,15 +150,16 @@ class Settings::LanguageModelsControllerTest < ActionDispatch::IntegrationTest assert_equal params, @language_model.reload.slice(:api_name, :name, :supports_images) end - test "update should update best language model" do + test "update language model works" do api_service = api_services(:keith_anthropic_service) - assert_equal api_service.language_models.best.pluck(:api_name), ["claude-best"] + initial_count = api_service.language_models.count another_language_model = language_models(:claude_3_opus_20240229) - patch settings_language_model_url(another_language_model), params: { language_model: {best: true}} + patch settings_language_model_url(another_language_model), params: { language_model: {supports_images: true}} assert_redirected_to settings_language_models_url - assert_equal api_service.language_models.best.pluck(:api_name), ["claude-3-opus-20240229"] + assert another_language_model.reload.supports_images? + assert_equal initial_count, api_service.language_models.count end test "destroy should soft-delete language_model" do diff --git a/test/fixtures/language_models.yml b/test/fixtures/language_models.yml index 0f1b55ed..d0394c9b 100644 --- a/test/fixtures/language_models.yml +++ b/test/fixtures/language_models.yml @@ -5,7 +5,6 @@ gemini-1.5-pro-002: name: Google Gemini 1.5 Pro (latest) api_service: keith_gemini_service api_name: gemini-1.5-pro-002 - best: true supports_images: true supports_tools: false supports_system_message: true @@ -124,7 +123,6 @@ gpt_best: position: 1 user: keith name: Best OpenAI Model - best: true api_name: gpt-best api_service: keith_openai_service supports_images: true @@ -136,7 +134,6 @@ claude_best: position: 2 user: keith name: Best Anthropic Model - best: true api_service: keith_anthropic_service api_name: claude-best supports_images: true diff --git a/test/models/api_service_test.rb b/test/models/api_service_test.rb index 71b56685..bef223dd 100644 --- a/test/models/api_service_test.rb +++ b/test/models/api_service_test.rb @@ -40,7 +40,7 @@ class APIServiceTest < ActiveSupport::TestCase assert_equal "new secret", api_service.token end - test "both ai_backends are specified for best models" do + test "both ai_backends are specified for language models" do assert_equal AIBackend::OpenAI, language_models(:gpt_best).ai_backend assert_equal AIBackend::Anthropic, language_models(:claude_best).ai_backend end diff --git a/test/models/language_model/export_test.rb b/test/models/language_model/export_test.rb index 698b4f53..8d554231 100644 --- a/test/models/language_model/export_test.rb +++ b/test/models/language_model/export_test.rb @@ -21,7 +21,7 @@ class LanguageModel::ExportTest < ActiveSupport::TestCase assert File.exist?(path) storage = JSON.load_file(path) models = storage["models"] - assert_equal models.first.keys.sort, %w[api_name name best supports_images supports_tools supports_system_message api_service_name].sort + assert_equal models.first.keys.sort, %w[api_name name supports_images supports_tools supports_system_message api_service_name].sort end test "export_to_file yaml" do @@ -30,7 +30,7 @@ class LanguageModel::ExportTest < ActiveSupport::TestCase assert File.exist?(path) storage = YAML.load_file(path) models = storage["models"] - assert_equal models.first.keys.sort, %w[api_name name best supports_images supports_tools supports_system_message api_service_name].sort + assert_equal models.first.keys.sort, %w[api_name name supports_images supports_tools supports_system_message api_service_name].sort end test "import_from_file with only new models" do