Skip to content

Commit

Permalink
Rename base executor to llama.cpp and added default config
Browse files Browse the repository at this point in the history
  • Loading branch information
Vadser committed Aug 14, 2024
1 parent f5683fe commit 5bb3eb1
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 8 deletions.
9 changes: 9 additions & 0 deletions app/helpers/model_versions_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
# frozen_string_literal: true

module ModelVersionsHelper
DEFAULT_CONFIGURATION = {
'openai' => '{"model":"gpt-3.5-turbo","temperature":0.5}',
'ollama' => '{"model":"llama3.1"}',
'llama' => '{"n_predict":500,"temperature":0.5,"stop":["<|end|>","<|user|>","<|assistant|>","<|endoftext|>","<|system|>"]}'
}.freeze

def default_configuration(executor_type)
DEFAULT_CONFIGURATION[executor_type] || {}.to_json
end
end
2 changes: 2 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import { application } from "controllers/application"
import AssertionController from "./assertion_controller"
import AssertionResultModalController from "./assertion_result_modal_controller"
import ModelController from "./model_controller"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)
application.register("assertion", AssertionController)
application.register("assertionResultModal", AssertionResultModalController)
application.register("model", ModelController)

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
Expand Down
25 changes: 25 additions & 0 deletions app/javascript/controllers/model_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Controller } from "@hotwired/stimulus"
const DEFAULT_CONFIGURATION = {
openai: '{"model":"gpt-3.5-turbo","temperature":0.5}',
ollama: '{"model":"llama3.1"}',
llama: '{"n_predict":500,"temperature":0.5,"stop":["<|end|>","<|user|>","<|assistant|>","<|endoftext|>","<|system|>"]}'
}

export default class extends Controller {
static targets = ["configurationField", "apiKeyField"]

connect() {
this.toggleConfiguration()
}

toggleConfiguration() {
const executorType = this.element.querySelector('#executor_type_selector').value
if (this.hasConfigurationFieldTarget)
this.configurationFieldTarget.value = DEFAULT_CONFIGURATION[executorType]

if (executorType == 'openai')
this.apiKeyFieldTarget.style.display = "block"
else
this.apiKeyFieldTarget.style.display = "none"
}
}
2 changes: 1 addition & 1 deletion app/models/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Model < ApplicationRecord
has_many :model_versions, dependent: :destroy
accepts_nested_attributes_for :model_versions, allow_destroy: true, reject_if: :all_blank

enum :executor_type, { base: 0, openai: 1, ollama: 2 }, scopes: false, default: :base
enum :executor_type, { llama: 0, openai: 1, ollama: 2 }, scopes: false, default: :llama

default_scope { order(id: :desc) }
end
6 changes: 6 additions & 0 deletions app/services/executors/llama.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

module Executors
class Llama < Base
end
end
2 changes: 1 addition & 1 deletion app/views/model_versions/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<div class="my-5">
<%= form.label :configuration %>
<%= form.text_field :configuration, value: (model_version&.configuration || {})&.to_json, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
<%= form.text_field :configuration, value: JSON::dump(model_version&.configuration) || default_configuration(@model.executor_type), class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
</div>

<div class="my-5">
Expand Down
8 changes: 4 additions & 4 deletions app/views/models/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= form_with(model: model, class: "contents") do |form| %>
<%= form_with(model: model, class: "contents", data: { controller: "model" }) do |form| %>
<% if model.errors.any? %>
<div id="error_explanation" class="bg-red-50 text-red-500 px-3 py-2 font-medium rounded-lg mt-3">
<h2><%= pluralize(model.errors.count, "error") %> prohibited this model from being saved:</h2>
Expand All @@ -23,10 +23,10 @@

<div class="mb-4">
<%= form.label :executor_type, class: "block text-gray-700 text-sm font-bold mb-2" %>
<%= form.select :executor_type, Model.executor_types.keys.map { |w| [w.humanize, w] }, {}, class: "block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-2 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500" %>
<%= form.select :executor_type, Model.executor_types.keys.map { |w| [I18n.t("activerecord.attributes.model.executor_types.#{w}"), w] }, {}, class: "block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-2 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500", id: "executor_type_selector", data: { action: "change->model#toggleConfiguration" } %>
</div>

<div class="my-5">
<div id="api_key_field" data-model-target="apiKeyField" class="my-5" style="<%= model.executor_type == 'openai' ? '' : 'display:none;' %>">
<%= form.label :api_key %>
<%= form.text_field :api_key, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
</div>
Expand All @@ -35,7 +35,7 @@
<%= form.fields_for :model_versions, @model_version do |model_version_fields| %>
<div class="my-5">
<%= model_version_fields.label :configuration %>
<%= model_version_fields.text_field :configuration, value: {}.to_json , class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
<%= model_version_fields.text_field :configuration, value: default_configuration(model.executor_type), 'data-model-target' => "configurationField", class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %>
</div>

<div class="my-5">
Expand Down
7 changes: 7 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,10 @@

en:
hello: "Hello world"
activerecord:
attributes:
model:
executor_types:
llama: 'Llama.cpp'
openai: 'OpenAI'
ollama: 'Ollama'
2 changes: 1 addition & 1 deletion spec/factories/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
factory :model do
name { 'Test Model' }
url { 'http://example.com' }
executor_type { 'base' }
executor_type { 'llama' }
api_key { 'apikey' }
association :user
end
Expand Down
55 changes: 55 additions & 0 deletions spec/services/executors/llama_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# frozen_string_literal: true

require 'rails_helper'
require 'webmock/rspec'

RSpec.describe Executors::Llama do
describe '#call' do
let(:model) { create(:model, url: 'http://example.com/model_endpoint') }
let(:model_version) { create(:model_version, model:, configuration: { param: 'value' }) }
let(:executor) { Executors::Base.new(model_version) }
let(:prompt) { 'Test prompt' }

context 'when HTTP request is successful' do
before do
stub_request(:post, 'http://example.com/model_endpoint')
.with(
body: '{"param":"value","prompt":"Test prompt"}',
headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
'Content-Type' => 'application/json',
'User-Agent' => 'Ruby'
}
)
.to_return(status: 200, body: '{"response": "Test response"}', headers: {})
end

it 'returns a completed status with result on successful response' do
expect(executor.call(prompt)).to eq({ status: :completed, result: '{"response": "Test response"}' })
end
end

context 'when HTTP request fails' do
before do
stub_request(:post, 'http://example.com/model_endpoint')
.to_return(status: 500, body: 'Internal Server Error')
end

it 'returns a failed status' do
expect(executor.call(prompt)).to eq({ status: :failed, result: 'Internal Server Error' })
end
end

context 'when HTTP request times out' do
before do
stub_request(:post, 'http://example.com/model_endpoint')
.to_timeout
end

it 'returns a failed status' do
expect(executor.call(prompt)).to eq({ result: { error: { message: 'execution expired' } }.to_json, status: :failed })
end
end
end
end
2 changes: 1 addition & 1 deletion spec/services/model_executor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
end

context "when executor type is 'base'" do
let(:model) { create(:model, executor_type: 'base') }
let(:model) { create(:model, executor_type: 'llama') }
let(:model_version) { create(:model_version, model:) }
let(:prompt) { 'Test prompt' }
let(:executor_instance) { instance_double(Executors::Base) }
Expand Down

0 comments on commit 5bb3eb1

Please sign in to comment.