From 12fe76abd4ca0777fcadee30a4994d1333ed47dd Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 09:25:31 +1000 Subject: [PATCH 1/7] Import LanguageModels from models.yaml --- README.md | 28 +++ app/models/concerns/language_model/export.rb | 41 ++++ app/models/language_model.rb | 3 + lib/tasks/models.rake | 15 ++ models.yaml | 198 +++++++++++++++++++ test/models/language_model_test.rb | 66 +++++++ 6 files changed, 351 insertions(+) create mode 100644 app/models/concerns/language_model/export.rb create mode 100644 lib/tasks/models.rake create mode 100644 models.yaml diff --git a/README.md b/README.md index 2cbf9bd43..85994f921 100644 --- a/README.md +++ b/README.md @@ -368,6 +368,34 @@ HostedGPT requires these services to be running: Every time you pull new changes down, kill `bin/dev` and then re-run it. This will ensure your local app picks up changes to Gemfile and migrations. +## Language models + +Each User has their own list of Language Models they can use. + +### Refreshing language models + +There is a shared list of known LLM models for OpenAI, Anthropic, and Groq in `models.yaml` and a Rake task to import them into all users: + +```plain +rails models:import +``` + +### Update models.yaml + +The `models.yaml` file in the root of the project is used by HostedGPT applications to refresh their local list of models. + +To refresh this file using the models in local DB, run: + +```plain +rails models:export +``` + +To export the models to another file, either json or yaml, pass in an argument: + +```plain +rails models:export[tmp/models.json] +``` + ### Running tests If you're set up with Docker you run `docker compose run base rails test`. Note that the system tests, which use a headless browser, are not able to run in Docker. They will be run automatically for you if you create a Pull Request against the project. diff --git a/app/models/concerns/language_model/export.rb b/app/models/concerns/language_model/export.rb new file mode 100644 index 000000000..52f90c463 --- /dev/null +++ b/app/models/concerns/language_model/export.rb @@ -0,0 +1,41 @@ +module LanguageModel::Export + extend ActiveSupport::Concern + + def as_json(options = {}) + options = options.with_indifferent_access + attrs = super(options) + attrs["api_service_name"] = api_service_name if options[:only].include?(:api_service_name) + attrs + end + + class_methods do + def export_to_file(path:, models:, only: %i[api_name name api_service_name supports_images supports_tools input_token_cost_cents output_token_cost_cents]) + path = path.to_s + storage = { + "models" => models.as_json(only:) + } + if path.ends_with?(".json") + File.write(path, storage.to_json) + else + File.write(path, storage.to_yaml) + end + end + + def import_from_file(path:, users: User.all) + users = Array.wrap(users) + storage = YAML.load_file(path) + models = storage["models"] + models.each do |model| + model = model.with_indifferent_access + users.each do |user| + lm = user.language_models.find_or_initialize_by(api_name: model[:api_name]) + lm.api_service = user.api_services.find_by(name: model[:api_service_name]) if model[:api_service_name] + lm.attributes = model.except(:api_service_name) + lm.save! + rescue ActiveRecord::RecordInvalid => e + warn "Failed to import '#{model[:api_name]}': #{e.message} for #{model.inspect}" + end + end + end + end +end diff --git a/app/models/language_model.rb b/app/models/language_model.rb index e813e307f..55324feab 100644 --- a/app/models/language_model.rb +++ b/app/models/language_model.rb @@ -1,5 +1,7 @@ # We don"t care about large or not class LanguageModel < ApplicationRecord + include LanguageModel::Export + belongs_to :user belongs_to :api_service @@ -18,6 +20,7 @@ class LanguageModel < ApplicationRecord 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 def created_by_current_user? user == Current.user diff --git a/lib/tasks/models.rake b/lib/tasks/models.rake new file mode 100644 index 000000000..03a33798b --- /dev/null +++ b/lib/tasks/models.rake @@ -0,0 +1,15 @@ +namespace :models do + desc "Export language models to a file, defaulting to models.yaml" + task :export, [:path] => :environment do |t, args| + args.with_defaults(path: Rails.root.join("models.yaml")) + models = User.first.language_models.not_deleted.includes(:api_service) + LanguageModel.export_to_file(path: args[:path], models:) + end + + desc "Import language models to all users from a file, defaulting to models.yaml" + task :import, [:path] => :environment do |t, args| + args.with_defaults(path: Rails.root.join("models.yaml")) + users = User.all + LanguageModel.import_from_file(path: args[:path], users:) + end +end diff --git a/models.yaml b/models.yaml new file mode 100644 index 000000000..418a57107 --- /dev/null +++ b/models.yaml @@ -0,0 +1,198 @@ +--- +models: +- api_name: gpt-4o-2024-08-06 + name: GPT-4o Omni Multimodal (2024-08-06) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.00025' + output_token_cost_cents: '0.001' + 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 + input_token_cost_cents: '0.0005' + output_token_cost_cents: '0.0015' + api_service_name: OpenAI +- api_name: gpt-4-turbo + name: GPT-4 Turbo with Vision (latest) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + 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 + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + api_service_name: OpenAI +- api_name: gpt-4-turbo-preview + name: GPT-4 Turbo Preview + supports_images: false + supports_tools: true + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + api_service_name: OpenAI +- api_name: gpt-4-0125-preview + name: GPT-4 Turbo Preview (2024-01-25) + supports_images: false + supports_tools: true + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + api_service_name: OpenAI +- api_name: gpt-4-1106-preview + name: GPT-4 Turbo Preview (2023-11-06) + supports_images: false + supports_tools: true + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + 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 + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + 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 + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + api_service_name: OpenAI +- api_name: gpt-4 + name: GPT-4 (latest) + supports_images: false + supports_tools: true + input_token_cost_cents: '0.003' + output_token_cost_cents: '0.006' + 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 + input_token_cost_cents: '0.001' + output_token_cost_cents: '0.003' + api_service_name: OpenAI +- api_name: gpt-3.5-turbo + name: GPT-3.5 Turbo (latest) + supports_images: false + supports_tools: true + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0006' + 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 + input_token_cost_cents: '0.00005' + output_token_cost_cents: '0.00015' + 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 + input_token_cost_cents: '0.0001' + output_token_cost_cents: '0.0002' + api_service_name: OpenAI +- api_name: gpt-3.5-turbo-instruct + name: GPT-3.5 Turbo Instruct + supports_images: false + supports_tools: false + input_token_cost_cents: '0.00015' + output_token_cost_cents: '0.0002' + 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 + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0004' + api_service_name: OpenAI +- api_name: gpt-4o + name: GPT-4o (latest) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.00025' + output_token_cost_cents: '0.001' + api_service_name: OpenAI +- api_name: claude-3-opus-20240229 + name: Claude 3 Opus (2024-02-29) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.0015' + output_token_cost_cents: '0.0075' + api_service_name: Anthropic +- api_name: claude-3-sonnet-20240229 + name: Claude 3 Sonnet (2024-02-29) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0015' + api_service_name: Anthropic +- api_name: claude-3-haiku-20240307 + name: Claude 3 Haiku (2024-03-07) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.000025' + output_token_cost_cents: '0.000125' + api_service_name: Anthropic +- api_name: claude-2.1 + name: Claude 2.1 + supports_images: false + supports_tools: true + input_token_cost_cents: '0.0008' + output_token_cost_cents: '0.0024' + api_service_name: Anthropic +- api_name: claude-2.0 + name: Claude 2.0 + supports_images: false + supports_tools: true + input_token_cost_cents: '0.0008' + output_token_cost_cents: '0.0024' + api_service_name: Anthropic +- api_name: claude-instant-1.2 + name: Claude Instant 1.2 + supports_images: false + supports_tools: true + input_token_cost_cents: '0.00008' + output_token_cost_cents: '0.00024' + api_service_name: Anthropic +- api_name: claude-3-5-sonnet-20240620 + name: Claude 3.5 Sonnet (2024-06-20) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0015' + api_service_name: Anthropic +- api_name: llama3-8b-8192 + name: Meta Llama 3 8b + supports_images: false + supports_tools: true + input_token_cost_cents: '0.000005' + output_token_cost_cents: '0.000008' + api_service_name: Groq +- api_name: mixtral-8x7b-32768 + name: Mistral 8 7b + supports_images: false + supports_tools: true + input_token_cost_cents: '0.000024' + output_token_cost_cents: '0.000024' + api_service_name: Groq +- api_name: gemma-7b-it + name: Google Gemma 7b + supports_images: false + supports_tools: true + input_token_cost_cents: '0.000007' + output_token_cost_cents: '0.000007' + api_service_name: Groq +- api_name: llama3-70b-8192 + name: Meta Llama 3 70b + supports_images: false + supports_tools: true + input_token_cost_cents: '0.000059' + output_token_cost_cents: '0.000079' + api_service_name: Groq diff --git a/test/models/language_model_test.rb b/test/models/language_model_test.rb index 31944055e..85620fe1b 100644 --- a/test/models/language_model_test.rb +++ b/test/models/language_model_test.rb @@ -81,6 +81,72 @@ class LanguageModelTest < ActiveSupport::TestCase assert list.include?("alpaca:medium") end + # Functionality in LanguageModel::Export concern + test "export_to_file json" do + path = Rails.root.join("tmp/models.json") + LanguageModel.export_to_file(path:, models: users(:rob).language_models.not_deleted) + assert File.exist?(path) + storage = JSON.load_file(path) + models = storage["models"] + assert_equal models.first.keys, %w[api_name name supports_images supports_tools input_token_cost_cents output_token_cost_cents api_service_name] + end + + test "export_to_file yaml" do + path = Rails.root.join("tmp/models.yaml") + LanguageModel.export_to_file(path:, models: users(:rob).language_models.not_deleted) + assert File.exist?(path) + storage = YAML.load_file(path) + models = storage["models"] + assert_equal models.first.keys, %w[api_name name supports_images supports_tools input_token_cost_cents output_token_cost_cents api_service_name] + end + + test "import_from_file with only new models" do + models = [{ + api_name: "new-model", + name: "new model", + api_service_name: api_services(:rob_openai_service).name, + supports_images: true, + supports_tools: true, + input_token_cost_cents: 1, + output_token_cost_cents: 1 + }] + storage = { + "models" => models + } + path = Rails.root.join("tmp/newmodels.yaml") + File.write(path, storage.to_yaml) + assert_difference "LanguageModel.count", 1 do + LanguageModel.import_from_file(path:, users: users(:rob)) + end + assert users(:rob).language_models.find_by(api_name: "new-model") + end + + test "import_from_file with existing models by api_name" do + model = users(:rob).language_models.not_deleted.first + models = [{ + api_name: model.api_name, + name: "new name", + supports_images: false, + supports_tools: true, + input_token_cost_cents: 0.0001, + output_token_cost_cents: 0.0001 + }] + storage = { + "models" => models + } + path = Rails.root.join("tmp/newmodels.yaml") + File.write(path, storage.to_yaml) + assert_no_difference "LanguageModel.count" do + LanguageModel.import_from_file(path:, users: users(:rob)) + end + model.reload + assert_equal "new name", model.name + assert_equal false, model.supports_images + assert_equal true, model.supports_tools + assert_equal 0.0001, model.input_token_cost_cents + assert_equal 0.0001, model.output_token_cost_cents + end + private def create_params From a48a5d02c337db6a3218b65398771a5e346f39a3 Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 09:28:19 +1000 Subject: [PATCH 2/7] Clean up language of export task --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 85994f921..e2d544909 100644 --- a/README.md +++ b/README.md @@ -384,13 +384,13 @@ rails models:import The `models.yaml` file in the root of the project is used by HostedGPT applications to refresh their local list of models. -To refresh this file using the models in local DB, run: +To refresh the `models.yaml` file using the models in local DB, run: ```plain rails models:export ``` -To export the models to another file, either json or yaml, pass in an argument: +If you want to export the models in the local DB to another file, either `.json` or `.yaml`, pass in an argument: ```plain rails models:export[tmp/models.json] From 2e21113b3acc8313f4d26b143f672816fe7ba6e9 Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 09:53:10 +1000 Subject: [PATCH 3/7] Add supports_system_message to export --- app/models/concerns/language_model/export.rb | 13 ++- models.yaml | 84 +++++++++++++------- 2 files changed, 68 insertions(+), 29 deletions(-) diff --git a/app/models/concerns/language_model/export.rb b/app/models/concerns/language_model/export.rb index 52f90c463..38a9e6baa 100644 --- a/app/models/concerns/language_model/export.rb +++ b/app/models/concerns/language_model/export.rb @@ -8,8 +8,19 @@ def as_json(options = {}) attrs end + DEFAULT_EXPORT_ONLY = %i[ + api_name + name + api_service_name + supports_images + supports_tools + supports_system_message + input_token_cost_cents + output_token_cost_cents + ] + class_methods do - def export_to_file(path:, models:, only: %i[api_name name api_service_name supports_images supports_tools input_token_cost_cents output_token_cost_cents]) + def export_to_file(path:, models:, only: DEFAULT_EXPORT_ONLY) path = path.to_s storage = { "models" => models.as_json(only:) diff --git a/models.yaml b/models.yaml index 418a57107..d0d14fe94 100644 --- a/models.yaml +++ b/models.yaml @@ -1,11 +1,20 @@ --- models: +- api_name: gpt-4o + name: GPT-4o (latest) + supports_images: true + supports_tools: true + input_token_cost_cents: '0.00025' + output_token_cost_cents: '0.001' + supports_system_message: true + api_service_name: OpenAI - api_name: gpt-4o-2024-08-06 name: GPT-4o Omni Multimodal (2024-08-06) supports_images: true supports_tools: true input_token_cost_cents: '0.00025' output_token_cost_cents: '0.001' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4o-2024-05-13 name: GPT-4o Omni Multimodal (2024-05-13) @@ -13,6 +22,7 @@ models: supports_tools: true input_token_cost_cents: '0.0005' output_token_cost_cents: '0.0015' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo name: GPT-4 Turbo with Vision (latest) @@ -20,6 +30,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + 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) @@ -27,6 +38,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo-preview name: GPT-4 Turbo Preview @@ -34,6 +46,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-0125-preview name: GPT-4 Turbo Preview (2024-01-25) @@ -41,6 +54,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-1106-preview name: GPT-4 Turbo Preview (2023-11-06) @@ -48,6 +62,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-vision-preview name: GPT-4 Turbo with Vision Preview (2023-11-06) @@ -55,6 +70,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + 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) @@ -62,6 +78,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4 name: GPT-4 (latest) @@ -69,6 +86,7 @@ models: supports_tools: true input_token_cost_cents: '0.003' output_token_cost_cents: '0.006' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-0613 name: GPT-4 Snapshot improved function calling (2023-06-13) @@ -76,6 +94,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo name: GPT-3.5 Turbo (latest) @@ -83,6 +102,7 @@ models: supports_tools: true input_token_cost_cents: '0.0003' output_token_cost_cents: '0.0006' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo-0125 name: GPT-3.5 Turbo (2022-01-25) @@ -90,6 +110,7 @@ models: supports_tools: true input_token_cost_cents: '0.00005' output_token_cost_cents: '0.00015' + supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo-1106 name: GPT-3.5 Turbo (2022-11-06) @@ -97,27 +118,7 @@ models: supports_tools: true input_token_cost_cents: '0.0001' output_token_cost_cents: '0.0002' - api_service_name: OpenAI -- api_name: gpt-3.5-turbo-instruct - name: GPT-3.5 Turbo Instruct - supports_images: false - supports_tools: false - input_token_cost_cents: '0.00015' - output_token_cost_cents: '0.0002' - 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 - input_token_cost_cents: '0.0003' - output_token_cost_cents: '0.0004' - api_service_name: OpenAI -- api_name: gpt-4o - name: GPT-4o (latest) - supports_images: true - supports_tools: true - input_token_cost_cents: '0.00025' - output_token_cost_cents: '0.001' + supports_system_message: true api_service_name: OpenAI - api_name: claude-3-opus-20240229 name: Claude 3 Opus (2024-02-29) @@ -125,6 +126,7 @@ models: supports_tools: true input_token_cost_cents: '0.0015' output_token_cost_cents: '0.0075' + supports_system_message: true api_service_name: Anthropic - api_name: claude-3-sonnet-20240229 name: Claude 3 Sonnet (2024-02-29) @@ -132,13 +134,31 @@ models: supports_tools: true input_token_cost_cents: '0.0003' output_token_cost_cents: '0.0015' + supports_system_message: true api_service_name: Anthropic +- api_name: gpt-3.5-turbo-instruct + name: GPT-3.5 Turbo Instruct + supports_images: false + supports_tools: false + input_token_cost_cents: '0.00015' + output_token_cost_cents: '0.0002' + 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 + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0004' + supports_system_message: false + api_service_name: OpenAI - api_name: claude-3-haiku-20240307 name: Claude 3 Haiku (2024-03-07) supports_images: true supports_tools: true input_token_cost_cents: '0.000025' output_token_cost_cents: '0.000125' + supports_system_message: true api_service_name: Anthropic - api_name: claude-2.1 name: Claude 2.1 @@ -146,6 +166,7 @@ models: supports_tools: true input_token_cost_cents: '0.0008' output_token_cost_cents: '0.0024' + supports_system_message: true api_service_name: Anthropic - api_name: claude-2.0 name: Claude 2.0 @@ -153,6 +174,7 @@ models: supports_tools: true input_token_cost_cents: '0.0008' output_token_cost_cents: '0.0024' + supports_system_message: true api_service_name: Anthropic - api_name: claude-instant-1.2 name: Claude Instant 1.2 @@ -160,6 +182,7 @@ models: supports_tools: true input_token_cost_cents: '0.00008' output_token_cost_cents: '0.00024' + supports_system_message: true api_service_name: Anthropic - api_name: claude-3-5-sonnet-20240620 name: Claude 3.5 Sonnet (2024-06-20) @@ -167,13 +190,23 @@ models: supports_tools: true input_token_cost_cents: '0.0003' output_token_cost_cents: '0.0015' + supports_system_message: true api_service_name: Anthropic +- api_name: llama3-70b-8192 + name: Meta Llama 3 70b + supports_images: false + supports_tools: true + input_token_cost_cents: '0.000059' + output_token_cost_cents: '0.000079' + supports_system_message: true + api_service_name: Groq - api_name: llama3-8b-8192 name: Meta Llama 3 8b supports_images: false supports_tools: true input_token_cost_cents: '0.000005' output_token_cost_cents: '0.000008' + supports_system_message: true api_service_name: Groq - api_name: mixtral-8x7b-32768 name: Mistral 8 7b @@ -181,6 +214,7 @@ models: supports_tools: true input_token_cost_cents: '0.000024' output_token_cost_cents: '0.000024' + supports_system_message: true api_service_name: Groq - api_name: gemma-7b-it name: Google Gemma 7b @@ -188,11 +222,5 @@ models: supports_tools: true input_token_cost_cents: '0.000007' output_token_cost_cents: '0.000007' - api_service_name: Groq -- api_name: llama3-70b-8192 - name: Meta Llama 3 70b - supports_images: false - supports_tools: true - input_token_cost_cents: '0.000059' - output_token_cost_cents: '0.000079' + supports_system_message: true api_service_name: Groq From dd553670e12218787d2f21aa25dfb9c0ca5b1479 Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 09:55:33 +1000 Subject: [PATCH 4/7] Add best to export; sort export models --- app/models/concerns/language_model/export.rb | 1 + lib/tasks/models.rake | 2 +- models.yaml | 92 +++++++++++++------- test/models/language_model_test.rb | 4 +- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/app/models/concerns/language_model/export.rb b/app/models/concerns/language_model/export.rb index 38a9e6baa..2613919f6 100644 --- a/app/models/concerns/language_model/export.rb +++ b/app/models/concerns/language_model/export.rb @@ -11,6 +11,7 @@ def as_json(options = {}) DEFAULT_EXPORT_ONLY = %i[ api_name name + best api_service_name supports_images supports_tools diff --git a/lib/tasks/models.rake b/lib/tasks/models.rake index 03a33798b..beb015735 100644 --- a/lib/tasks/models.rake +++ b/lib/tasks/models.rake @@ -2,7 +2,7 @@ namespace :models do desc "Export language models to a file, defaulting to models.yaml" task :export, [:path] => :environment do |t, args| args.with_defaults(path: Rails.root.join("models.yaml")) - models = User.first.language_models.not_deleted.includes(:api_service) + models = User.first.language_models.ordered.not_deleted.includes(:api_service) LanguageModel.export_to_file(path: args[:path], models:) end diff --git a/models.yaml b/models.yaml index d0d14fe94..03002ee39 100644 --- a/models.yaml +++ b/models.yaml @@ -6,14 +6,34 @@ models: supports_tools: true input_token_cost_cents: '0.00025' output_token_cost_cents: '0.001' + best: true 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 + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0015' + best: true + supports_system_message: true + api_service_name: Anthropic +- api_name: llama3-70b-8192 + name: Meta Llama 3 70b + supports_images: false + supports_tools: true + input_token_cost_cents: '0.000059' + output_token_cost_cents: '0.000079' + 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 input_token_cost_cents: '0.00025' output_token_cost_cents: '0.001' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4o-2024-05-13 @@ -22,6 +42,7 @@ models: supports_tools: true input_token_cost_cents: '0.0005' output_token_cost_cents: '0.0015' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo @@ -30,6 +51,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo-2024-04-09 @@ -38,6 +60,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-turbo-preview @@ -46,6 +69,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-0125-preview @@ -54,6 +78,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-1106-preview @@ -62,6 +87,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-vision-preview @@ -70,6 +96,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-1106-vision-preview @@ -78,6 +105,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4 @@ -86,6 +114,7 @@ models: supports_tools: true input_token_cost_cents: '0.003' output_token_cost_cents: '0.006' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-4-0613 @@ -94,6 +123,7 @@ models: supports_tools: true input_token_cost_cents: '0.001' output_token_cost_cents: '0.003' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo @@ -102,6 +132,7 @@ models: supports_tools: true input_token_cost_cents: '0.0003' output_token_cost_cents: '0.0006' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo-0125 @@ -110,6 +141,7 @@ models: supports_tools: true input_token_cost_cents: '0.00005' output_token_cost_cents: '0.00015' + best: false supports_system_message: true api_service_name: OpenAI - api_name: gpt-3.5-turbo-1106 @@ -118,6 +150,7 @@ models: supports_tools: true input_token_cost_cents: '0.0001' output_token_cost_cents: '0.0002' + best: false supports_system_message: true api_service_name: OpenAI - api_name: claude-3-opus-20240229 @@ -126,6 +159,7 @@ models: supports_tools: true input_token_cost_cents: '0.0015' output_token_cost_cents: '0.0075' + best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-3-sonnet-20240229 @@ -134,30 +168,16 @@ models: supports_tools: true input_token_cost_cents: '0.0003' output_token_cost_cents: '0.0015' + best: false supports_system_message: true api_service_name: Anthropic -- api_name: gpt-3.5-turbo-instruct - name: GPT-3.5 Turbo Instruct - supports_images: false - supports_tools: false - input_token_cost_cents: '0.00015' - output_token_cost_cents: '0.0002' - 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 - input_token_cost_cents: '0.0003' - output_token_cost_cents: '0.0004' - supports_system_message: false - api_service_name: OpenAI - api_name: claude-3-haiku-20240307 name: Claude 3 Haiku (2024-03-07) supports_images: true supports_tools: true input_token_cost_cents: '0.000025' output_token_cost_cents: '0.000125' + best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-2.1 @@ -166,6 +186,7 @@ models: supports_tools: true input_token_cost_cents: '0.0008' output_token_cost_cents: '0.0024' + best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-2.0 @@ -174,6 +195,7 @@ models: supports_tools: true input_token_cost_cents: '0.0008' output_token_cost_cents: '0.0024' + best: false supports_system_message: true api_service_name: Anthropic - api_name: claude-instant-1.2 @@ -182,30 +204,16 @@ models: supports_tools: true input_token_cost_cents: '0.00008' output_token_cost_cents: '0.00024' + best: false supports_system_message: true api_service_name: Anthropic -- api_name: claude-3-5-sonnet-20240620 - name: Claude 3.5 Sonnet (2024-06-20) - supports_images: true - supports_tools: true - input_token_cost_cents: '0.0003' - output_token_cost_cents: '0.0015' - supports_system_message: true - api_service_name: Anthropic -- api_name: llama3-70b-8192 - name: Meta Llama 3 70b - supports_images: false - supports_tools: true - input_token_cost_cents: '0.000059' - output_token_cost_cents: '0.000079' - supports_system_message: true - api_service_name: Groq - api_name: llama3-8b-8192 name: Meta Llama 3 8b supports_images: false supports_tools: true input_token_cost_cents: '0.000005' output_token_cost_cents: '0.000008' + best: false supports_system_message: true api_service_name: Groq - api_name: mixtral-8x7b-32768 @@ -214,6 +222,7 @@ models: supports_tools: true input_token_cost_cents: '0.000024' output_token_cost_cents: '0.000024' + best: false supports_system_message: true api_service_name: Groq - api_name: gemma-7b-it @@ -222,5 +231,24 @@ models: supports_tools: true input_token_cost_cents: '0.000007' output_token_cost_cents: '0.000007' + 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 + input_token_cost_cents: '0.00015' + output_token_cost_cents: '0.0002' + 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 + input_token_cost_cents: '0.0003' + output_token_cost_cents: '0.0004' + best: false + supports_system_message: false + api_service_name: OpenAI diff --git a/test/models/language_model_test.rb b/test/models/language_model_test.rb index 85620fe1b..eb6926e69 100644 --- a/test/models/language_model_test.rb +++ b/test/models/language_model_test.rb @@ -88,7 +88,7 @@ class LanguageModelTest < ActiveSupport::TestCase assert File.exist?(path) storage = JSON.load_file(path) models = storage["models"] - assert_equal models.first.keys, %w[api_name name supports_images supports_tools input_token_cost_cents output_token_cost_cents api_service_name] + assert_equal models.first.keys.sort, %w[api_name name best supports_images supports_tools supports_system_message input_token_cost_cents output_token_cost_cents api_service_name].sort end test "export_to_file yaml" do @@ -97,7 +97,7 @@ class LanguageModelTest < ActiveSupport::TestCase assert File.exist?(path) storage = YAML.load_file(path) models = storage["models"] - assert_equal models.first.keys, %w[api_name name supports_images supports_tools input_token_cost_cents output_token_cost_cents api_service_name] + assert_equal models.first.keys.sort, %w[api_name name best supports_images supports_tools supports_system_message input_token_cost_cents output_token_cost_cents api_service_name].sort end test "import_from_file with only new models" do From 473c45315e6661a009fed1dc6f693dd4a1363a6b Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 10:05:31 +1000 Subject: [PATCH 5/7] New users load models from models.yaml --- app/models/concerns/language_model/export.rb | 6 +- app/models/user/registerable.rb | 63 +------------------- lib/tasks/models.rake | 4 +- 3 files changed, 7 insertions(+), 66 deletions(-) diff --git a/app/models/concerns/language_model/export.rb b/app/models/concerns/language_model/export.rb index 2613919f6..009bfe123 100644 --- a/app/models/concerns/language_model/export.rb +++ b/app/models/concerns/language_model/export.rb @@ -20,8 +20,10 @@ def as_json(options = {}) output_token_cost_cents ] + DEFAULT_MODEL_FILE = "models.yaml" + class_methods do - def export_to_file(path:, models:, only: DEFAULT_EXPORT_ONLY) + def export_to_file(path: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE), models:, only: DEFAULT_EXPORT_ONLY) path = path.to_s storage = { "models" => models.as_json(only:) @@ -33,7 +35,7 @@ def export_to_file(path:, models:, only: DEFAULT_EXPORT_ONLY) end end - def import_from_file(path:, users: User.all) + def import_from_file(path: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE), users: User.all) users = Array.wrap(users) storage = YAML.load_file(path) models = storage["models"] diff --git a/app/models/user/registerable.rb b/app/models/user/registerable.rb index 6b01380e2..bf7417a27 100644 --- a/app/models/user/registerable.rb +++ b/app/models/user/registerable.rb @@ -12,68 +12,7 @@ def create_initial_assistants_etc anthropic_api_service = api_services.create!(url: APIService::URL_ANTHROPIC, driver: :anthropic, name: "Anthropic") groq_api_service = api_services.create!(url: APIService::URL_GROQ, driver: :openai, name: "Groq") - best_models = %w[gpt-4o claude-3-5-sonnet-20240620 llama3-70b-8192] - [ - ["gpt-4o", "GPT-4o (latest)", true, open_ai_api_service, 250, 1000], - ["gpt-4o-2024-08-06", "GPT-4o Omni Multimodal (2024-08-06)", true, open_ai_api_service, 250, 1000], - ["gpt-4o-2024-05-13", "GPT-4o Omni Multimodal (2024-05-13)", true, open_ai_api_service, 500, 1500], - - ["gpt-4-turbo", "GPT-4 Turbo with Vision (latest)", true, open_ai_api_service, 1000, 3000], - ["gpt-4-turbo-2024-04-09", "GPT-4 Turbo with Vision (2024-04-09)", true, open_ai_api_service, 1000, 3000], - ["gpt-4-turbo-preview", "GPT-4 Turbo Preview", false, open_ai_api_service, 1000, 3000], - ["gpt-4-0125-preview", "GPT-4 Turbo Preview (2024-01-25)", false, open_ai_api_service, 1000, 3000], - ["gpt-4-1106-preview", "GPT-4 Turbo Preview (2023-11-06)", false, open_ai_api_service, 1000, 3000], - ["gpt-4-vision-preview", "GPT-4 Turbo with Vision Preview (2023-11-06)", true, open_ai_api_service, 1000, 3000], - ["gpt-4-1106-vision-preview", "GPT-4 Turbo with Vision Preview (2023-11-06)", true, open_ai_api_service, 1000, 3000], - - ["gpt-4", "GPT-4 (latest)", false, open_ai_api_service, 3000, 6000], - ["gpt-4-0613", "GPT-4 Snapshot improved function calling (2023-06-13)", false, open_ai_api_service, 1000, 3000], - - ["gpt-3.5-turbo", "GPT-3.5 Turbo (latest)", false, open_ai_api_service, 300, 600], - ["gpt-3.5-turbo-0125", "GPT-3.5 Turbo (2022-01-25)", false, open_ai_api_service, 50, 150], - ["gpt-3.5-turbo-1106", "GPT-3.5 Turbo (2022-11-06)", false, open_ai_api_service, 100, 200], - - ["claude-3-5-sonnet-20240620", "Claude 3.5 Sonnet (2024-06-20)", true, anthropic_api_service, 300, 1500], - ["claude-3-opus-20240229", "Claude 3 Opus (2024-02-29)", true, anthropic_api_service, 1500, 7500], - ["claude-3-sonnet-20240229", "Claude 3 Sonnet (2024-02-29)", true, anthropic_api_service, 300, 1500], - ["claude-3-haiku-20240307", "Claude 3 Haiku (2024-03-07)", true, anthropic_api_service, 25, 125], - ["claude-2.1", "Claude 2.1", false, anthropic_api_service, 800, 2400], - ["claude-2.0", "Claude 2.0", false, anthropic_api_service, 800, 2400], - ["claude-instant-1.2", "Claude Instant 1.2", false, anthropic_api_service, 80, 240], - - ["llama3-70b-8192", "Meta Llama 3 70b", false, groq_api_service, 59, 79], - ["llama3-8b-8192", "Meta Llama 3 8b", false, groq_api_service, 5, 8], - ["mixtral-8x7b-32768", "Mistral 8 7b", false, groq_api_service, 24, 24], - ["gemma-7b-it", "Google Gemma 7b", false, groq_api_service, 7, 7], - ].each do |api_name, name, supports_images, api_service, input_token_cost_per_million, output_token_cost_per_million| - million = BigDecimal(1_000_000) - input_token_cost_cents = input_token_cost_per_million/million - output_token_cost_cents = output_token_cost_per_million/million - - language_models.create!( - api_name:, - api_service:, - name:, - best: best_models.include?(api_name), - supports_tools: true, - supports_system_message: true, - supports_images:, - input_token_cost_cents:, - output_token_cost_cents:, - ) - end - - # Only these don't support tools: - [ - ["gpt-3.5-turbo-instruct", "GPT-3.5 Turbo Instruct", false, open_ai_api_service, 150, 200], - ["gpt-3.5-turbo-16k-0613", "GPT-3.5 Turbo (2022-06-13)", false, open_ai_api_service, 300, 400], - ].each do |api_name, name, supports_images, api_service, input_token_cost_per_million, output_token_cost_per_million| - million = BigDecimal(1_000_000) - input_token_cost_cents = input_token_cost_per_million/million - output_token_cost_cents = output_token_cost_per_million/million - - language_models.create!(api_name:, api_service:, name:, supports_tools: false, supports_system_message: false, supports_images:, input_token_cost_cents:, output_token_cost_cents:) - end + LanguageModel.import_from_file(users: [self]) assistants.create! name: "GPT-4o", language_model: language_models.best_for_api_service(open_ai_api_service).first assistants.create! name: "Claude 3.5 Sonnet", language_model: language_models.best_for_api_service(anthropic_api_service).first diff --git a/lib/tasks/models.rake b/lib/tasks/models.rake index beb015735..76b19ba71 100644 --- a/lib/tasks/models.rake +++ b/lib/tasks/models.rake @@ -1,14 +1,14 @@ namespace :models do desc "Export language models to a file, defaulting to models.yaml" task :export, [:path] => :environment do |t, args| - args.with_defaults(path: Rails.root.join("models.yaml")) + args.with_defaults(path: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE)) models = User.first.language_models.ordered.not_deleted.includes(:api_service) LanguageModel.export_to_file(path: args[:path], models:) end desc "Import language models to all users from a file, defaulting to models.yaml" task :import, [:path] => :environment do |t, args| - args.with_defaults(path: Rails.root.join("models.yaml")) + args.with_defaults(path: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE)) users = User.all LanguageModel.import_from_file(path: args[:path], users:) end From 3d7523a6606716127646aee88aad173c1692499c Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 11:00:50 +1000 Subject: [PATCH 6/7] Remove unused data-only migrations --- db/migrate/20240624100000_add_groq.rb | 22 +------ ...te_existing_language_models_with_prices.rb | 58 ------------------- .../20241022053212_update_model_prices.rb | 55 ------------------ 3 files changed, 1 insertion(+), 134 deletions(-) delete mode 100644 db/migrate/20240911114059_update_existing_language_models_with_prices.rb delete mode 100644 db/migrate/20241022053212_update_model_prices.rb diff --git a/db/migrate/20240624100000_add_groq.rb b/db/migrate/20240624100000_add_groq.rb index 3fc87474c..a44d90959 100644 --- a/db/migrate/20240624100000_add_groq.rb +++ b/db/migrate/20240624100000_add_groq.rb @@ -7,28 +7,8 @@ def up User.all.find_each do |user| groq_api_service = user.api_services.create!(url: APIService::URL_GROQ, driver: :openai, name: "Groq") - language_model = user.language_models.create!(position: 3, api_name: LanguageModel::BEST_GROQ, api_service: groq_api_service, name: "Best Open-Source Model", supports_images: false) - user.language_models.where("position >= 3").where.not(id: language_model.id).find_each do |model| - model.update(position: model.position + 1) - end - [ - ["llama3-70b-8192", "Meta Llama 3 70b", false, groq_api_service], - ["llama3-8b-8192", "Meta Llama 3 8b", false, groq_api_service], - ["mixtral-8x7b-32768", "Mistral 8 7b", false, groq_api_service], - ["gemma-7b-it", "Google Gemma 7b", false, groq_api_service], - ].each do |api_name, name, supports_images, api_service| - user.language_models.create!(api_name: api_name, api_service: api_service, name: name, supports_images: supports_images) - end - - [ "GPT-3.5", "Claude 3 Opus" ].each do |name| - asst = user.assistants.find_by(name: name) - next if asst.nil? - asst.deleted! if asst.conversations.count == 0 - asst.deleted! if asst.conversations.count == 1 && asst.conversations.first.messages.count <= 2 - end - - user.assistants.create!(name: "Meta Llama 3 70b", language_model: language_model) + user.assistants.create! name: "Meta Llama 3 70b", language_model: language_models.best_for_api_service(groq_api_service).first end end diff --git a/db/migrate/20240911114059_update_existing_language_models_with_prices.rb b/db/migrate/20240911114059_update_existing_language_models_with_prices.rb deleted file mode 100644 index f5e9939db..000000000 --- a/db/migrate/20240911114059_update_existing_language_models_with_prices.rb +++ /dev/null @@ -1,58 +0,0 @@ -class UpdateExistingLanguageModelsWithPrices < ActiveRecord::Migration[7.1] - def up - [ - # Constant was removed in a later PR - # - # [LanguageModel::BEST_GPT, LanguageModel::BEST_MODEL_INPUT_PRICES[LanguageModel::BEST_GPT], LanguageModel::BEST_MODEL_OUTPUT_PRICES[LanguageModel::BEST_GPT]], - # [LanguageModel::BEST_CLAUDE, LanguageModel::BEST_MODEL_INPUT_PRICES[LanguageModel::BEST_CLAUDE], LanguageModel::BEST_MODEL_OUTPUT_PRICES[LanguageModel::BEST_CLAUDE]], - # [LanguageModel::BEST_GROQ, LanguageModel::BEST_MODEL_INPUT_PRICES[LanguageModel::BEST_GROQ], LanguageModel::BEST_MODEL_OUTPUT_PRICES[LanguageModel::BEST_GROQ]], - - ["gpt-4o", 500, 1500], - ["gpt-4o-2024-05-13", 500, 1500], - - ["gpt-4-turbo", 1000, 3000], - ["gpt-4-turbo-2024-04-09", 1000, 3000], - ["gpt-4-turbo-preview", 1000, 3000], # not sure on price - ["gpt-4-0125-preview", 1000, 3000], - ["gpt-4-1106-preview", 1000, 3000], - ["gpt-4-vision-preview", 1000, 3000], - ["gpt-4-1106-vision-preview", 1000, 3000], # not sure on price - - ["gpt-4", 3000, 6000], - ["gpt-4-0613", 1000, 3000], # not sure on price - - ["gpt-3.5-turbo", 300, 600], - ["gpt-3.5-turbo-0125", 50, 150], - ["gpt-3.5-turbo-1106", 100, 200], - - ["claude-3-5-sonnet-20240620",300, 1500], - ["claude-3-opus-20240229", 1500, 7500], - ["claude-3-sonnet-20240229", 300, 1500], - ["claude-3-haiku-20240307", 25, 125], - ["claude-2.1", 800, 2400], - ["claude-2.0", 800, 2400], - ["claude-instant-1.2", 80, 240], - - ["llama3-70b-8192", 59, 79], - ["llama3-8b-8192", 5, 8], - ["mixtral-8x7b-32768", 24, 24], - ["gemma-7b-it", 7, 7], - - ["gpt-3.5-turbo-instruct", 150, 200], - ["gpt-3.5-turbo-16k-0613", 300, 400], - ].each do |api_name, input_token_cost_per_million, output_token_cost_per_million| - million = BigDecimal(1_000_000) - input_token_cost_cents = input_token_cost_per_million/million - output_token_cost_cents = output_token_cost_per_million/million - - LanguageModel.where(api_name: api_name).update_all( - input_token_cost_cents: input_token_cost_cents, - output_token_cost_cents: output_token_cost_cents, - ) - end - end - - def down - # nothing to do - end -end diff --git a/db/migrate/20241022053212_update_model_prices.rb b/db/migrate/20241022053212_update_model_prices.rb deleted file mode 100644 index e229bf0bc..000000000 --- a/db/migrate/20241022053212_update_model_prices.rb +++ /dev/null @@ -1,55 +0,0 @@ -class UpdateModelPrices < ActiveRecord::Migration[7.1] - def up - [ - # Constant was removed in a later PR - # [LanguageModel::BEST_GPT, LanguageModel::BEST_MODEL_INPUT_PRICES[LanguageModel::BEST_GPT], LanguageModel::BEST_MODEL_OUTPUT_PRICES[LanguageModel::BEST_GPT]], - - ["gpt-4o", 250, 1000], - ].each do |api_name, input_token_cost_per_million, output_token_cost_per_million| - million = BigDecimal(1_000_000) - input_token_cost_cents = input_token_cost_per_million/million - output_token_cost_cents = output_token_cost_per_million/million - - LanguageModel.where(api_name: api_name).update_all( - input_token_cost_cents: input_token_cost_cents, - output_token_cost_cents: output_token_cost_cents, - ) - end - - # add new model too - User.find_each do |user| - open_ai_api_service = user.api_services.find_or_create_by!(url: APIService::URL_OPEN_AI, driver: :openai, name: "OpenAI") - - [ - ["gpt-4o-2024-08-06", "GPT-4o Omni Multimodal (2024-08-06)", true, open_ai_api_service, 250, 1000], - ].each do |api_name, name, supports_images, api_service, input_token_cost_per_million, output_token_cost_per_million| - unless user.language_models.exists?(api_name: api_name) # don't add if it already exists - million = BigDecimal(1_000_000) - input_token_cost_cents = input_token_cost_per_million/million - output_token_cost_cents = output_token_cost_per_million/million - - LanguageModel.skip_callback(:save, :after, :update_best_language_model_for_api_service) - - begin - user.language_models.create!( - api_name: api_name, - name: name, - supports_images: supports_images, - api_service: api_service, - supports_tools: true, - input_token_cost_cents: input_token_cost_cents, - output_token_cost_cents: output_token_cost_cents, - ) - ensure - LanguageModel.set_callback(:save, :after, :update_best_language_model_for_api_service) - end - end - end - end - - end - - def down - # nothing to do - end -end From b433bc32b89d88b8ff07308c19324c38d0338b90 Mon Sep 17 00:00:00 2001 From: Dr Nic Williams Date: Mon, 18 Nov 2024 11:07:37 +1000 Subject: [PATCH 7/7] Document new user behavior --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index e2d544909..312d2f0fa 100644 --- a/README.md +++ b/README.md @@ -372,6 +372,10 @@ Every time you pull new changes down, kill `bin/dev` and then re-run it. This wi Each User has their own list of Language Models they can use. +When a new User is created (when a person registers for the first time), they are initialized with a long list of models. This list is loaded from `models.yaml`. + +When an administrator upgrades their deployment of HostedGPT, they can update the available models for all users with a task `rails models:import`. + ### Refreshing language models There is a shared list of known LLM models for OpenAI, Anthropic, and Groq in `models.yaml` and a Rake task to import them into all users: @@ -390,12 +394,20 @@ To refresh the `models.yaml` file using the models in local DB, run: rails models:export ``` +### Alternate export file + If you want to export the models in the local DB to another file, either `.json` or `.yaml`, pass in an argument: ```plain rails models:export[tmp/models.json] ``` +To import from another file, similarly provide the path as an argument: + +```plain +rails models:import[tmp/models.json] +``` + ### Running tests If you're set up with Docker you run `docker compose run base rails test`. Note that the system tests, which use a headless browser, are not able to run in Docker. They will be run automatically for you if you create a Pull Request against the project.