-
Notifications
You must be signed in to change notification settings - Fork 239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Import LanguageModels from models.yaml #556
base: main
Are you sure you want to change the base?
Changes from all commits
12fe76a
a48a5d0
2e21113
dd55367
473c453
3d7523a
b433bc3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
module LanguageModel::Export | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the file path, I've always followed the convention that the So to keep consistent with the rest of the models concerns, I'd move this to |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I got an exception in rails console when I did We don't necessarily need to support all those different edge cases, but out of curiosity I was asking chatgpt if there was a more idiomatic way to support delegate attributes with as_json since this is a common pattern. I don't think there is, but ChatGPT wrote this code as a suggestion (I didn't test this):
|
||
|
||
DEFAULT_EXPORT_ONLY = %i[ | ||
api_name | ||
name | ||
best | ||
api_service_name | ||
supports_images | ||
supports_tools | ||
supports_system_message | ||
input_token_cost_cents | ||
output_token_cost_cents | ||
] | ||
|
||
DEFAULT_MODEL_FILE = "models.yaml" | ||
|
||
class_methods do | ||
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:) | ||
} | ||
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: Rails.root.join(LanguageModel::Export::DEFAULT_MODEL_FILE), 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
# We don"t care about large or not | ||
class LanguageModel < ApplicationRecord | ||
include LanguageModel::Export | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When you move the concern file, this can be updated to |
||
|
||
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 | ||
|
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(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(LanguageModel::Export::DEFAULT_MODEL_FILE)) | ||
users = User.all | ||
LanguageModel.import_from_file(path: args[:path], users:) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that export checks the file extension for json vs yaml, but it does not look like import supports json so we should change this documented example to be yaml or add support for json (but I think it's also fine for us to support json export but not import)