Skip to content

Commit ebb86de

Browse files
authored
Merge branch 'main' into assistants-page
2 parents d242213 + 83d1b69 commit ebb86de

File tree

18 files changed

+589
-207
lines changed

18 files changed

+589
-207
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,46 @@ HostedGPT requires these services to be running:
368368

369369
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.
370370

371+
## Language models
372+
373+
Each User has their own list of Language Models they can use.
374+
375+
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.yml`.
376+
377+
When an administrator upgrades their deployment of HostedGPT, they can update the available models for all users with a task `rails models:import`.
378+
379+
### Refreshing language models
380+
381+
There is a shared list of known LLM models for OpenAI, Anthropic, and Groq in `models.yml` and a Rake task to import them into all users:
382+
383+
```plain
384+
rails models:import
385+
```
386+
387+
### Update models.yml
388+
389+
The `models.yml` file in the root of the project is used by HostedGPT applications to refresh their local list of models.
390+
391+
To refresh the `models.yml` file using the models in local DB, run:
392+
393+
```plain
394+
rails models:export
395+
```
396+
397+
### Alternate export file
398+
399+
If you want to export the models in the local DB to another file, either `.json` or `.yaml`, pass in an argument:
400+
401+
```plain
402+
rails models:export[tmp/models.json]
403+
```
404+
405+
To import from another file, similarly provide the path as an argument:
406+
407+
```plain
408+
rails models:import[tmp/models.json]
409+
```
410+
371411
### Running tests
372412

373413
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.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
class Settings::MemoriesController < Settings::ApplicationController
2+
before_action :set_memory, only: :destroy
3+
24
def index
35
@memories = Current.user.memories.includes(:message)
46
end
57

68
def destroy
9+
@memory.destroy!
10+
redirect_to settings_memories_url, notice: "Forgotten", status: :see_other
11+
end
12+
13+
def destroy_all
714
Current.user.memories.delete_all
815
redirect_to settings_memories_url, notice: "Cleared memory", status: :see_other
916
end
17+
18+
private
19+
20+
def set_memory
21+
@memory = Current.user.memories.find_by(id: params[:id])
22+
end
1023
end

app/models/language_model.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# We don"t care about large or not
22
class LanguageModel < ApplicationRecord
3+
include Export
4+
35
belongs_to :user
46
belongs_to :api_service
57

@@ -18,6 +20,7 @@ class LanguageModel < ApplicationRecord
1820
scope :best_for_api_service, ->(api_service) { where(best: true, api_service: api_service) }
1921

2022
delegate :ai_backend, to: :api_service
23+
delegate :name, to: :api_service, prefix: true, allow_nil: true
2124

2225
def created_by_current_user?
2326
user == Current.user

app/models/language_model/export.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
module LanguageModel::Export
2+
extend ActiveSupport::Concern
3+
4+
DEFAULT_EXPORT_ONLY = %i[
5+
api_name
6+
name
7+
best
8+
api_service_name
9+
supports_images
10+
supports_tools
11+
supports_system_message
12+
input_token_cost_cents
13+
output_token_cost_cents
14+
]
15+
16+
DEFAULT_MODEL_FILE = "models.yml"
17+
18+
def attributes
19+
super.merge("api_service_name" => api_service_name)
20+
end
21+
22+
# Unsure why this needs to re-defined, but the original ActiveModel::Serialization
23+
# implementation is ignoring the #attributes method above.
24+
def attribute_names_for_serialization
25+
attributes.keys
26+
end
27+
28+
class_methods do
29+
def export_to_file(path: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE), models:, only: DEFAULT_EXPORT_ONLY)
30+
path = path.to_s
31+
storage = {
32+
"models" => models.as_json(only:)
33+
}
34+
if path.ends_with?(".json")
35+
File.write(path, storage.to_json)
36+
else
37+
File.write(path, storage.to_yaml)
38+
end
39+
end
40+
41+
def import_from_file(path: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE), users: User.all)
42+
users = Array.wrap(users)
43+
storage = YAML.load_file(path)
44+
models = storage["models"]
45+
models.each do |model|
46+
model = model.with_indifferent_access
47+
users.each do |user|
48+
lm = user.language_models.find_or_initialize_by(api_name: model[:api_name])
49+
lm.api_service = user.api_services.find_by(name: model[:api_service_name]) if model[:api_service_name]
50+
lm.attributes = model.except(:api_service_name)
51+
lm.save!
52+
rescue ActiveRecord::RecordInvalid => e
53+
warn "Failed to import '#{model[:api_name]}': #{e.message} for #{model.inspect}"
54+
end
55+
end
56+
end
57+
end
58+
end

app/models/user/registerable.rb

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -12,68 +12,7 @@ def create_initial_assistants_etc
1212
anthropic_api_service = api_services.create!(url: APIService::URL_ANTHROPIC, driver: :anthropic, name: "Anthropic")
1313
groq_api_service = api_services.create!(url: APIService::URL_GROQ, driver: :openai, name: "Groq")
1414

15-
best_models = %w[gpt-4o claude-3-5-sonnet-20240620 llama3-70b-8192]
16-
[
17-
["gpt-4o", "GPT-4o (latest)", true, open_ai_api_service, 250, 1000],
18-
["gpt-4o-2024-08-06", "GPT-4o Omni Multimodal (2024-08-06)", true, open_ai_api_service, 250, 1000],
19-
["gpt-4o-2024-05-13", "GPT-4o Omni Multimodal (2024-05-13)", true, open_ai_api_service, 500, 1500],
20-
21-
["gpt-4-turbo", "GPT-4 Turbo with Vision (latest)", true, open_ai_api_service, 1000, 3000],
22-
["gpt-4-turbo-2024-04-09", "GPT-4 Turbo with Vision (2024-04-09)", true, open_ai_api_service, 1000, 3000],
23-
["gpt-4-turbo-preview", "GPT-4 Turbo Preview", false, open_ai_api_service, 1000, 3000],
24-
["gpt-4-0125-preview", "GPT-4 Turbo Preview (2024-01-25)", false, open_ai_api_service, 1000, 3000],
25-
["gpt-4-1106-preview", "GPT-4 Turbo Preview (2023-11-06)", false, open_ai_api_service, 1000, 3000],
26-
["gpt-4-vision-preview", "GPT-4 Turbo with Vision Preview (2023-11-06)", true, open_ai_api_service, 1000, 3000],
27-
["gpt-4-1106-vision-preview", "GPT-4 Turbo with Vision Preview (2023-11-06)", true, open_ai_api_service, 1000, 3000],
28-
29-
["gpt-4", "GPT-4 (latest)", false, open_ai_api_service, 3000, 6000],
30-
["gpt-4-0613", "GPT-4 Snapshot improved function calling (2023-06-13)", false, open_ai_api_service, 1000, 3000],
31-
32-
["gpt-3.5-turbo", "GPT-3.5 Turbo (latest)", false, open_ai_api_service, 300, 600],
33-
["gpt-3.5-turbo-0125", "GPT-3.5 Turbo (2022-01-25)", false, open_ai_api_service, 50, 150],
34-
["gpt-3.5-turbo-1106", "GPT-3.5 Turbo (2022-11-06)", false, open_ai_api_service, 100, 200],
35-
36-
["claude-3-5-sonnet-20240620", "Claude 3.5 Sonnet (2024-06-20)", true, anthropic_api_service, 300, 1500],
37-
["claude-3-opus-20240229", "Claude 3 Opus (2024-02-29)", true, anthropic_api_service, 1500, 7500],
38-
["claude-3-sonnet-20240229", "Claude 3 Sonnet (2024-02-29)", true, anthropic_api_service, 300, 1500],
39-
["claude-3-haiku-20240307", "Claude 3 Haiku (2024-03-07)", true, anthropic_api_service, 25, 125],
40-
["claude-2.1", "Claude 2.1", false, anthropic_api_service, 800, 2400],
41-
["claude-2.0", "Claude 2.0", false, anthropic_api_service, 800, 2400],
42-
["claude-instant-1.2", "Claude Instant 1.2", false, anthropic_api_service, 80, 240],
43-
44-
["llama3-70b-8192", "Meta Llama 3 70b", false, groq_api_service, 59, 79],
45-
["llama3-8b-8192", "Meta Llama 3 8b", false, groq_api_service, 5, 8],
46-
["mixtral-8x7b-32768", "Mistral 8 7b", false, groq_api_service, 24, 24],
47-
["gemma-7b-it", "Google Gemma 7b", false, groq_api_service, 7, 7],
48-
].each do |api_name, name, supports_images, api_service, input_token_cost_per_million, output_token_cost_per_million|
49-
million = BigDecimal(1_000_000)
50-
input_token_cost_cents = input_token_cost_per_million/million
51-
output_token_cost_cents = output_token_cost_per_million/million
52-
53-
language_models.create!(
54-
api_name:,
55-
api_service:,
56-
name:,
57-
best: best_models.include?(api_name),
58-
supports_tools: true,
59-
supports_system_message: true,
60-
supports_images:,
61-
input_token_cost_cents:,
62-
output_token_cost_cents:,
63-
)
64-
end
65-
66-
# Only these don't support tools:
67-
[
68-
["gpt-3.5-turbo-instruct", "GPT-3.5 Turbo Instruct", false, open_ai_api_service, 150, 200],
69-
["gpt-3.5-turbo-16k-0613", "GPT-3.5 Turbo (2022-06-13)", false, open_ai_api_service, 300, 400],
70-
].each do |api_name, name, supports_images, api_service, input_token_cost_per_million, output_token_cost_per_million|
71-
million = BigDecimal(1_000_000)
72-
input_token_cost_cents = input_token_cost_per_million/million
73-
output_token_cost_cents = output_token_cost_per_million/million
74-
75-
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:)
76-
end
15+
LanguageModel.import_from_file(users: [self])
7716

7817
[
7918
["GPT-4o", open_ai_api_service],
Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
1-
<li class="list-disc py-1">
2-
<%= memory.detail %>
3-
<%= link_to_source(memory).html_safe %>
4-
</li>
1+
<tr class="py-1 <%= cycle('bg-gray-100 dark:bg-gray-600', 'bg-white dark:bg-gray-900') %>">
2+
<td>
3+
<%= memory.detail %>
4+
<%= link_to_source(memory).html_safe if memory.message.present? %>
5+
</td>
6+
<td>
7+
<%= button_to settings_memory_path(memory), method: :delete, class: "inline-block cursor-pointer py-1 pt-0 align-middle" do %>
8+
<%= icon "trash",
9+
variant: :outline,
10+
size: 22,
11+
class: %|
12+
stroke-2
13+
text-zinc-600 group-hover:text-zinc-900 dark:text-zinc-400 dark:group-hover:text-white
14+
|,
15+
title: "Forget",
16+
tooltip: :bottom
17+
%>
18+
<% end %>
19+
</td>
20+
</tr>

app/views/settings/memories/index.html.erb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@
2525
<% end %>
2626
</p>
2727

28-
<ul class="pl-6">
28+
<table id="memories" class="w-full table-auto border-b border-gray-300 dark:border-b-0">
29+
<thead>
30+
<tr class="bg-gray-200 dark:bg-gray-900">
31+
<th>Memory</th>
32+
<th></th>
33+
</tr>
34+
</thead>
2935
<%= render @memories %>
30-
</ul>
36+
</table>
3137

3238
</div>

config/routes.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
resource :person, only: [:edit, :update]
1919
resources :language_models
2020
resources :api_services, except: [:show]
21-
resources :memories, only: [:index] do
22-
delete :destroy, on: :collection
21+
resources :memories, only: [:index, :destroy] do
22+
delete :destroy, to: 'memories#destroy_all', on: :collection
2323
end
2424
end
2525

db/migrate/20240624100000_add_groq.rb

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,8 @@ def up
77

88
User.all.find_each do |user|
99
groq_api_service = user.api_services.create!(url: APIService::URL_GROQ, driver: :openai, name: "Groq")
10-
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)
11-
user.language_models.where("position >= 3").where.not(id: language_model.id).find_each do |model|
12-
model.update(position: model.position + 1)
13-
end
1410

15-
[
16-
["llama3-70b-8192", "Meta Llama 3 70b", false, groq_api_service],
17-
["llama3-8b-8192", "Meta Llama 3 8b", false, groq_api_service],
18-
["mixtral-8x7b-32768", "Mistral 8 7b", false, groq_api_service],
19-
["gemma-7b-it", "Google Gemma 7b", false, groq_api_service],
20-
].each do |api_name, name, supports_images, api_service|
21-
user.language_models.create!(api_name: api_name, api_service: api_service, name: name, supports_images: supports_images)
22-
end
23-
24-
[ "GPT-3.5", "Claude 3 Opus" ].each do |name|
25-
asst = user.assistants.find_by(name: name)
26-
next if asst.nil?
27-
asst.deleted! if asst.conversations.count == 0
28-
asst.deleted! if asst.conversations.count == 1 && asst.conversations.first.messages.count <= 2
29-
end
30-
31-
user.assistants.create!(name: "Meta Llama 3 70b", language_model: language_model)
11+
user.assistants.create! name: "Meta Llama 3 70b", language_model: language_models.best_for_api_service(groq_api_service).first
3212
end
3313
end
3414

db/migrate/20240911114059_update_existing_language_models_with_prices.rb

Lines changed: 0 additions & 58 deletions
This file was deleted.

0 commit comments

Comments
 (0)