diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 8252e1e..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e029ed3 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,77 @@ +name: Ruby with PostgreSQL + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + test: + + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: ['3.3.0'] + + services: + db: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test_db + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby and PostgreSQL + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + mirror: 'bd' # Use the Brazilian mirror for faster downloads + + - name: Install PostgreSQL client + run: | + sudo apt-get install postgresql-client + + - name: Wait for PostgreSQL to be ready + run: | + until pg_isready -h localhost -p 5432 -U postgres; do + echo "Waiting for PostgreSQL to start..." + sleep 1 + done + - name: Generate creds file + run: | + EDITOR="mate --wait" ./bin/rails credentials:edit + + - name: Install Node.js and Yarn + run: | + curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash - + sudo apt-get install -y nodejs + npm install -g yarn + + - name: Yarn install + run: | + yarn install + + - name: Precompile assets + run: | + SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile + + - name: Setup database schema + run: | + # Replace with your database setup commands (e.g., migrations) + bundle exec rake db:create db:schema:load + + - name: Run tests + run: bundle exec rspec + + - name: Run rubocop + run: bundle exec rubocop -DES diff --git a/.gitignore b/.gitignore index f8579cd..6f8ffb9 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ /app/assets/builds/* !/app/assets/builds/.keep +.DS_Store diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..5be63fc --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--require spec_helper +--format documentation diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..2ed5182 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,59 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2024-07-15 13:37:11 UTC using RuboCop version 1.65.0. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 1 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include. +# Include: **/*.gemfile, **/Gemfile, **/gems.rb +Bundler/OrderedGems: + Exclude: + - 'Gemfile' + +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 66 + +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +# AllowedMethods: refine +Metrics/BlockLength: + Max: 155 + +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 9 + +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 74 + +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 9 + +# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. +# SupportedStyles: snake_case, normalcase, non_integer +# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 +Naming/VariableNumber: + Exclude: + - 'spec/controllers/*' + - 'spec/controllers/*' + +# Configuration parameters: AllowedConstants. +Style/Documentation: + Enabled: false + +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'bin/bundle' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 198 diff --git a/Dockerfile b/Dockerfile index f287da1..6c191f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,7 @@ WORKDIR /rails ENV RAILS_ENV="production" \ BUNDLE_DEPLOYMENT="1" \ BUNDLE_PATH="/usr/local/bundle" \ - BUNDLE_WITHOUT="development" \ - SECRET_KEY_BASE="a20aff0f4264e4896b81c5377418b46f104fdb209ded3d58b521abf871853adcabd0d904c569def108a35345e29b5e1affad36cb6619f0b51738f7de5d59b528" + BUNDLE_WITHOUT="development" # Throw-away build stage to reduce size of final image FROM base as build @@ -38,6 +37,10 @@ COPY . . # Install JavaScript dependencies RUN yarn install +RUN gem install rails + +RUN gem install foreman + # Precompile bootsnap code for faster boot times RUN bundle exec bootsnap precompile app/ lib/ @@ -56,6 +59,8 @@ RUN apt-get update -qq && \ COPY --from=build /usr/local/bundle /usr/local/bundle COPY --from=build /rails /rails +# Generate Rails master key and encrypt database credentials + # Run and own only the runtime files as a non-root user for security RUN useradd rails --create-home --shell /bin/bash && \ chown -R rails:rails db log storage tmp diff --git a/Gemfile b/Gemfile index c4a3f2a..4b9b2fa 100644 --- a/Gemfile +++ b/Gemfile @@ -1,30 +1,32 @@ -source "https://rubygems.org" +# frozen_string_literal: true -ruby "3.3.0" +source 'https://rubygems.org' + +ruby '3.3.0' # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem "rails", "~> 7.1.3", ">= 7.1.3.4" +gem 'rails', '~> 7.1.3', '>= 7.1.3.4' # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] -gem "sprockets-rails" +gem 'sprockets-rails' # Use sqlite3 as the database for Active Record -gem "sqlite3", "~> 1.4" +gem 'sqlite3', '~> 1.4' # Use the Puma web server [https://github.com/puma/puma] -gem "puma", ">= 5.0" +gem 'puma', '>= 5.0' # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] -gem "importmap-rails" +gem 'importmap-rails' # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] -gem "turbo-rails" +gem 'turbo-rails' # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] -gem "stimulus-rails" +gem 'stimulus-rails' # Build JSON APIs with ease [https://github.com/rails/jbuilder] -gem "jbuilder" +gem 'jbuilder' # Use Redis adapter to run Action Cable in production # gem "redis", ">= 4.0.1" @@ -36,24 +38,31 @@ gem "jbuilder" # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[ windows jruby ] +gem 'tzinfo-data', platforms: %i[windows jruby] # Reduces boot times through caching; required in config/boot.rb -gem "bootsnap", require: false +gem 'bootsnap', require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem + gem 'debug', platforms: %i[mri windows] + gem 'dotenv', '~> 3.1' + gem 'factory_bot_rails' gem 'pry' - gem "debug", platforms: %i[ mri windows ] - gem "dotenv", "~> 3.1" + gem 'rails-controller-testing' + gem 'rspec-rails', '~> 5.0.0' + gem 'rubocop', require: false + gem 'rubocop-rails', require: false + gem 'rubocop-performance', require: false + gem 'rubocop-rspec', require: false end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] - gem "web-console" + gem 'web-console' # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] # gem "rack-mini-profiler" @@ -64,17 +73,19 @@ end group :test do # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] - gem "capybara" - gem "selenium-webdriver" + gem 'capybara' + gem 'database_cleaner' + gem 'selenium-webdriver' + gem 'webmock', '~> 3.14' end -gem "ruby-openai", "~> 7.0" +gem 'ruby-openai', '~> 7.0' -gem "devise", "~> 4.9" -gem "devise-jwt", "~> 0.12.0" +gem 'devise', '~> 4.9' +gem 'devise-jwt', '~> 0.12.0' -gem "solid_queue", "~> 0.3.3" +gem 'solid_queue', '~> 0.3.3' -gem "tailwindcss-rails", "~> 2.6" +gem 'tailwindcss-rails', '~> 2.6' -gem "pg", "~> 1.5" +gem 'pg', '~> 1.5' diff --git a/Gemfile.lock b/Gemfile.lock index 4d1342e..6ad16ff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -77,6 +77,7 @@ GEM tzinfo (~> 2.0) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) + ast (2.4.2) base64 (0.2.0) bcrypt (3.1.20) bigdecimal (3.1.8) @@ -96,7 +97,16 @@ GEM coderay (1.1.3) concurrent-ruby (1.3.1) connection_pool (2.4.1) + crack (1.0.0) + bigdecimal + rexml crass (1.0.6) + database_cleaner (2.0.2) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.2.0) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) date (3.3.4) debug (1.9.2) irb (~> 1.10) @@ -110,6 +120,7 @@ GEM devise-jwt (0.12.1) devise (~> 4.0) warden-jwt_auth (~> 0.10) + diff-lcs (1.5.1) dotenv (3.1.2) drb (2.2.1) dry-auto_inject (1.0.1) @@ -125,6 +136,11 @@ GEM et-orbi (1.2.11) tzinfo event_stream_parser (1.0.0) + factory_bot (6.4.6) + activesupport (>= 5.0.0) + factory_bot_rails (6.4.3) + factory_bot (~> 6.4) + railties (>= 5.0.0) faraday (2.9.1) faraday-net_http (>= 2.0, < 3.2) faraday-multipart (1.0.4) @@ -136,6 +152,7 @@ GEM raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) + hashdiff (1.1.0) i18n (1.14.5) concurrent-ruby (~> 1.0) importmap-rails (2.0.1) @@ -149,8 +166,10 @@ GEM jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) + json (2.7.2) jwt (2.8.2) base64 + language_server-protocol (3.17.0.3) loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -192,6 +211,10 @@ GEM nokogiri (1.16.5-x86_64-linux) racc (~> 1.4) orm_adapter (0.5.0) + parallel (1.25.1) + parser (3.3.4.0) + ast (~> 2.4.1) + racc pg (1.5.6) pry (0.14.2) coderay (~> 1.1) @@ -225,6 +248,10 @@ GEM activesupport (= 7.1.3.4) bundler (>= 1.15.0) railties (= 7.1.3.4) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -240,6 +267,7 @@ GEM rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) + rainbow (3.1.1) rake (13.2.1) rdoc (6.7.0) psych (>= 4.0.0) @@ -251,10 +279,51 @@ GEM railties (>= 5.2) rexml (3.2.8) strscan (>= 3.0.9) + rspec-core (3.13.0) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-rails (5.0.3) + actionpack (>= 5.2) + activesupport (>= 5.2) + railties (>= 5.2) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-support (3.13.1) + rubocop (1.65.0) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.31.3) + parser (>= 3.3.1.0) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.25.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rspec (3.0.3) + rubocop (~> 1.61) ruby-openai (7.0.1) event_stream_parser (>= 0.3.0, < 2.0.0) faraday (>= 1) faraday-multipart (>= 1) + ruby-progressbar (1.13.0) rubyzip (2.3.2) selenium-webdriver (4.21.1) base64 (~> 0.2) @@ -304,6 +373,7 @@ GEM railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + unicode-display_width (2.5.0) uri (0.13.0) warden (1.2.9) rack (>= 2.0.9) @@ -317,6 +387,10 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webmock (3.23.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) websocket (1.2.10) websocket-driver (0.7.6) @@ -338,16 +412,24 @@ PLATFORMS DEPENDENCIES bootsnap capybara + database_cleaner debug devise (~> 4.9) devise-jwt (~> 0.12.0) dotenv (~> 3.1) + factory_bot_rails importmap-rails jbuilder pg (~> 1.5) pry puma (>= 5.0) rails (~> 7.1.3, >= 7.1.3.4) + rails-controller-testing + rspec-rails (~> 5.0.0) + rubocop + rubocop-performance + rubocop-rails + rubocop-rspec ruby-openai (~> 7.0) selenium-webdriver solid_queue (~> 0.3.3) @@ -358,6 +440,7 @@ DEPENDENCIES turbo-rails tzinfo-data web-console + webmock (~> 3.14) RUBY VERSION ruby 3.3.0p0 diff --git a/Rakefile b/Rakefile index 9a5ea73..488c551 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require_relative "config/application" +require_relative 'config/application' Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index d672697..9aec230 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 0ff5442..8d6c2a1 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Connection < ActionCable::Connection::Base end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c5268d9..b8546f7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base - protect_from_forgery with: :exception, if: Proc.new { |c| c.request.format != 'application/json' } - protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' } + protect_from_forgery with: :exception, if: proc { |c| c.request.format != 'application/json' } + protect_from_forgery with: :null_session, if: proc { |c| c.request.format == 'application/json' } before_action :authenticate_user! diff --git a/app/controllers/chats_controller.rb b/app/controllers/chats_controller.rb deleted file mode 100644 index 247ca77..0000000 --- a/app/controllers/chats_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -class ChatsController < ApplicationController - before_action :set_chat, only: %i[ show edit update destroy ] - - # GET /chats or /chats.json - def index - @chats = Chat.all - end - - # GET /chats/1 or /chats/1.json - def show - end - - # GET /chats/new - def new - @chat = Chat.new - end - - # GET /chats/1/edit - def edit - end - - # POST /chats or /chats.json - def create - @chat = Chat.new(chat_params) - - respond_to do |format| - if @chat.save - format.html { redirect_to chat_url(@chat), notice: "Chat was successfully created." } - format.json { render :show, status: :created, location: @chat } - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @chat.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /chats/1 or /chats/1.json - def update - respond_to do |format| - if @chat.update(chat_params) - format.html { redirect_to chat_url(@chat), notice: "Chat was successfully updated." } - format.json { render :show, status: :ok, location: @chat } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @chat.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /chats/1 or /chats/1.json - def destroy - @chat.destroy! - - respond_to do |format| - format.html { redirect_to chats_url, notice: "Chat was successfully destroyed." } - format.json { head :no_content } - end - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_chat - @chat = Chat.find(params[:id]) - end - - # Only allow a list of trusted parameters through. - def chat_params - params.require(:chat).permit(:title) - end -end diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index bc42217..1e6d9b1 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CompareController < ApplicationController def index @prompts = current_user.prompts diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 2473590..6049155 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DashboardController < ApplicationController def index; end end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb deleted file mode 100644 index a594dc0..0000000 --- a/app/controllers/messages_controller.rb +++ /dev/null @@ -1,79 +0,0 @@ -class MessagesController < ApplicationController - before_action :set_chat - before_action :set_message, only: %i[ show edit update destroy ] - - def index - @message = Message.new - @messages = Message.all - end - - def show - end - - def new - @message = Message.new - end - - def edit - end - - def create - @messages = Message.all - @message = @chat.messages.new(message_params) - - respond_to do |format| - if @message.save - # FIXME: this is a massive hack - # client = OpenAI::Client.new - # response = client.chat(parameters: { - # model: "gpt-3.5-turbo", - # messages: [{ role: "user", content: @message.body }], - # temperature: 0.5 - # }) - # Message.create body: "CHATGPT: " + response.dig("choices", 0, "message", "content") - # FIXME: the hack ends here - - format.html { redirect_to chat_message_url(@chat, @message), notice: "Message was successfully created." } - format.json { render :show, status: :created, location: @message } - format.turbo_stream - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @message.errors, status: :unprocessable_entity } - end - end - end - - def update - respond_to do |format| - if @message.update(message_params) - format.html { redirect_to chat_message_url(@chat, @message), notice: "Message was successfully updated." } - format.json { render :show, status: :ok, location: @message } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @message.errors, status: :unprocessable_entity } - end - end - end - - def destroy - @message.destroy! - - respond_to do |format| - format.html { redirect_to chat_messages_url(@chat), notice: "Message was successfully destroyed." } - format.json { head :no_content } - end - end - - private - def set_chat - @chat = Chat.find(params[:chat_id]) - end - - def set_message - @message = @chat.messages.find(params[:id]) - end - - def message_params - params.require(:message).permit(:body) - end -end diff --git a/app/controllers/model_versions_controller.rb b/app/controllers/model_versions_controller.rb index 680bd58..608acdd 100644 --- a/app/controllers/model_versions_controller.rb +++ b/app/controllers/model_versions_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class ModelVersionsController < ApplicationController before_action :set_model - before_action :set_model_version, only: %i[ show edit update destroy ] + before_action :set_model_version, only: %i[show edit update destroy] # GET /model_versions or /model_versions.json def index @@ -8,8 +10,7 @@ def index end # GET /model_versions/1 or /model_versions/1.json - def show - end + def show; end # GET /model_versions/new def new @@ -17,8 +18,7 @@ def new end # GET /model_versions/1/edit - def edit - end + def edit; end # POST /model_versions or /model_versions.json def create @@ -26,7 +26,9 @@ def create respond_to do |format| if @model_version.save - format.html { redirect_to model_model_version_url(@model, @model_version), notice: "Model version was successfully created." } + format.html do + redirect_to model_model_version_url(@model, @model_version), notice: 'Model version was successfully created.' + end format.json { render :show, status: :created, location: model_model_version_url(@model, @model_version) } else format.html { render :new, status: :unprocessable_entity } @@ -39,7 +41,9 @@ def create def update respond_to do |format| if @model_version.update(model_version_params) - format.html { redirect_to model_model_version_url(@model, @model_version), notice: "Model version was successfully updated." } + format.html do + redirect_to model_model_version_url(@model, @model_version), notice: 'Model version was successfully updated.' + end format.json { render :show, status: :ok, location: @model_version } else format.html { render :edit, status: :unprocessable_entity } @@ -53,12 +57,13 @@ def destroy @model_version.destroy! respond_to do |format| - format.html { redirect_to model_model_versions_url(@model), notice: "Model version was successfully destroyed." } + format.html { redirect_to model_model_versions_url(@model), notice: 'Model version was successfully destroyed.' } format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_model_version @model_version = @model.model_versions.find(params[:id]) diff --git a/app/controllers/models_controller.rb b/app/controllers/models_controller.rb index c0f48dc..d0bb4fe 100644 --- a/app/controllers/models_controller.rb +++ b/app/controllers/models_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class ModelsController < ApplicationController - before_action :set_model, only: %i[ show edit update destroy ] + before_action :set_model, only: %i[show edit update destroy] # GET /models or /models.json def index @@ -17,8 +19,7 @@ def new end # GET /models/1/edit - def edit - end + def edit; end # POST /models or /models.json def create @@ -26,7 +27,7 @@ def create respond_to do |format| if @model.save - format.html { redirect_to model_url(@model), notice: "Model successfully created." } + format.html { redirect_to model_url(@model), notice: 'Model successfully created.' } format.json { render :show, status: :created, location: @model } else format.html { render :new, status: :unprocessable_entity } @@ -39,7 +40,7 @@ def create def update respond_to do |format| if @model.update(model_params) - format.html { redirect_to model_url(@model), notice: "Model successfully updated." } + format.html { redirect_to model_url(@model), notice: 'Model successfully updated.' } format.json { render :show, status: :ok, location: @model } else format.html { render :edit, status: :unprocessable_entity } @@ -53,12 +54,13 @@ def destroy @model.destroy! respond_to do |format| - format.html { redirect_to models_url, notice: "Model successfully destroyed." } + format.html { redirect_to models_url, notice: 'Model successfully destroyed.' } format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_model @model = current_user.models.find(params[:id]) diff --git a/app/controllers/participants_controller.rb b/app/controllers/participants_controller.rb deleted file mode 100644 index c861fc5..0000000 --- a/app/controllers/participants_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -class ParticipantsController < ApplicationController - before_action :set_participant, only: %i[ show edit update destroy ] - - # GET /participants or /participants.json - def index - @participants = Participant.all - end - - # GET /participants/1 or /participants/1.json - def show - end - - # GET /participants/new - def new - @participant = Participant.new - end - - # GET /participants/1/edit - def edit - end - - # POST /participants or /participants.json - def create - @participant = Participant.new(participant_params) - - respond_to do |format| - if @participant.save - format.html { redirect_to participant_url(@participant), notice: "Participant was successfully created." } - format.json { render :show, status: :created, location: @participant } - else - format.html { render :new, status: :unprocessable_entity } - format.json { render json: @participant.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /participants/1 or /participants/1.json - def update - respond_to do |format| - if @participant.update(participant_params) - format.html { redirect_to participant_url(@participant), notice: "Participant was successfully updated." } - format.json { render :show, status: :ok, location: @participant } - else - format.html { render :edit, status: :unprocessable_entity } - format.json { render json: @participant.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /participants/1 or /participants/1.json - def destroy - @participant.destroy! - - respond_to do |format| - format.html { redirect_to participants_url, notice: "Participant was successfully destroyed." } - format.json { head :no_content } - end - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_participant - @participant = Participant.find(params[:id]) - end - - # Only allow a list of trusted parameters through. - def participant_params - params.require(:participant).permit(:name, :configuration, :implementor) - end -end diff --git a/app/controllers/prompts_controller.rb b/app/controllers/prompts_controller.rb index bc84b09..3ba6072 100644 --- a/app/controllers/prompts_controller.rb +++ b/app/controllers/prompts_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class PromptsController < ApplicationController - before_action :set_prompt, only: %i[ show destroy ] + before_action :set_prompt, only: %i[show destroy] # GET /prompts or /prompts.json def index @@ -22,7 +24,7 @@ def create respond_to do |format| if @prompt.save - format.html { redirect_to prompt_url(@prompt), notice: "Prompt was successfully created." } + format.html { redirect_to prompt_url(@prompt), notice: 'Prompt was successfully created.' } format.json { render :show, status: :created, location: @prompt } else format.html { render :new, status: :unprocessable_entity } @@ -36,12 +38,13 @@ def destroy @prompt.destroy! respond_to do |format| - format.html { redirect_to prompts_url, notice: "Prompt was successfully destroyed." } + format.html { redirect_to prompts_url, notice: 'Prompt was successfully destroyed.' } format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_prompt @prompt = current_user.prompts.find(params[:id]) diff --git a/app/controllers/test_results_controller.rb b/app/controllers/test_results_controller.rb index 50cf885..0d3459e 100644 --- a/app/controllers/test_results_controller.rb +++ b/app/controllers/test_results_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class TestResultsController < ApplicationController - before_action :set_test_result, only: [:show, :update] + before_action :set_test_result, only: %i[show update] def update if @test_result.update(test_results_params) @@ -12,7 +14,10 @@ def update def index @test_results = current_user.test_results.includes(model_version: :model).order(created_at: :desc) - @test_results = @test_results.where(model_version_id: params[:model_version_id], prompt_id: params[:prompt_id]) if params[:model_version_id].present? && params[:prompt_id].present? + if params[:model_version_id].present? && params[:prompt_id].present? + @test_results = @test_results.where(model_version_id: params[:model_version_id], + prompt_id: params[:prompt_id]) + end respond_to do |format| format.html { render :index } diff --git a/app/controllers/test_runs_controller.rb b/app/controllers/test_runs_controller.rb index 824ada3..ad65610 100644 --- a/app/controllers/test_runs_controller.rb +++ b/app/controllers/test_runs_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TestRunsController < ApplicationController before_action :set_prompt diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 886a869..51b2678 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationHelper def define_status_class(status) case status diff --git a/app/helpers/chats_helper.rb b/app/helpers/chats_helper.rb deleted file mode 100644 index cf92be3..0000000 --- a/app/helpers/chats_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ChatsHelper -end diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb deleted file mode 100644 index f1bca9f..0000000 --- a/app/helpers/messages_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module MessagesHelper -end diff --git a/app/helpers/model_versions_helper.rb b/app/helpers/model_versions_helper.rb index 4a3993d..eead013 100644 --- a/app/helpers/model_versions_helper.rb +++ b/app/helpers/model_versions_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ModelVersionsHelper end diff --git a/app/helpers/models_helper.rb b/app/helpers/models_helper.rb index d90a580..0fddda5 100644 --- a/app/helpers/models_helper.rb +++ b/app/helpers/models_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ModelsHelper end diff --git a/app/helpers/participants_helper.rb b/app/helpers/participants_helper.rb deleted file mode 100644 index 7059f83..0000000 --- a/app/helpers/participants_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ParticipantsHelper -end diff --git a/app/helpers/prompts_helper.rb b/app/helpers/prompts_helper.rb index 6ab8fce..76643bc 100644 --- a/app/helpers/prompts_helper.rb +++ b/app/helpers/prompts_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module PromptsHelper end diff --git a/app/helpers/test_runs_helper.rb b/app/helpers/test_runs_helper.rb index 72fc5ee..8959344 100644 --- a/app/helpers/test_runs_helper.rb +++ b/app/helpers/test_runs_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module TestRunsHelper end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index d394c3d..bef3959 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationJob < ActiveJob::Base # Automatically retry jobs that encountered a deadlock # retry_on ActiveRecord::Deadlocked diff --git a/app/jobs/test_run_job.rb b/app/jobs/test_run_job.rb index ca8e54a..5d1b7fb 100644 --- a/app/jobs/test_run_job.rb +++ b/app/jobs/test_run_job.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class TestRunJob < ApplicationJob def perform(model_version_id, prompt_id) model_version = ModelVersion.find(model_version_id) prompt = Prompt.find(prompt_id) - test_result = TestResult.create(model_version: model_version, prompt: prompt) + test_result = TestResult.create(model_version:, prompt:) result = {} benchmark = Benchmark.measure do diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 3c34c81..d84cb6e 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + class ApplicationMailer < ActionMailer::Base - default from: "from@example.com" - layout "mailer" + default from: 'from@example.com' + layout 'mailer' end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index b63caeb..08dc537 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationRecord < ActiveRecord::Base primary_abstract_class end diff --git a/app/models/chat.rb b/app/models/chat.rb deleted file mode 100644 index 447f26b..0000000 --- a/app/models/chat.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Chat < ApplicationRecord - has_many :messages, dependent: :destroy -end diff --git a/app/models/message.rb b/app/models/message.rb deleted file mode 100644 index 644a5cb..0000000 --- a/app/models/message.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Message < ApplicationRecord - belongs_to :chat - - validates :body, presence: true - validates :from, presence: true -end diff --git a/app/models/model.rb b/app/models/model.rb index d3dae0e..d8bbebb 100644 --- a/app/models/model.rb +++ b/app/models/model.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + class Model < ApplicationRecord encrypts :api_key belongs_to :user has_many :model_versions, dependent: :destroy - enum :executor_type, [ :base, :openai ], scopes: false, default: :base + enum :executor_type, %i[base openai], scopes: false, default: :base end diff --git a/app/models/model_version.rb b/app/models/model_version.rb index 18affed..0ced5ad 100644 --- a/app/models/model_version.rb +++ b/app/models/model_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ModelVersion < ApplicationRecord belongs_to :model has_many :test_results, dependent: :destroy diff --git a/app/models/participant.rb b/app/models/participant.rb deleted file mode 100644 index 770dc2b..0000000 --- a/app/models/participant.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Participant < ApplicationRecord - validates :name, presence: true -end diff --git a/app/models/prompt.rb b/app/models/prompt.rb index 6ef9d81..a6b1544 100644 --- a/app/models/prompt.rb +++ b/app/models/prompt.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Prompt < ApplicationRecord belongs_to :user has_many :test_results, dependent: :destroy diff --git a/app/models/test_result.rb b/app/models/test_result.rb index 8f38d3c..d312985 100644 --- a/app/models/test_result.rb +++ b/app/models/test_result.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + class TestResult < ApplicationRecord belongs_to :model_version belongs_to :prompt - enum :status, [ :pending, :completed, :failed ], scopes: true, default: :pending + enum :status, %i[pending completed failed], scopes: true, default: :pending - def as_json(options={}) + def as_json(options = {}) options[:methods] ||= [:content] super end @@ -12,12 +14,12 @@ def as_json(options={}) def content return '' if pending? - return JSON.parse(result).dig("error", "message") if failed? + return JSON.parse(result).dig('error', 'message') if failed? - return JSON.parse(result).dig("choices", 0, "message", "content") if model_version.executor_type == 'openai' + return JSON.parse(result).dig('choices', 0, 'message', 'content') if model_version.executor_type == 'openai' - return JSON.parse(result)['content'] if completed? - rescue + JSON.parse(result)['content'] if completed? + rescue StandardError '' end end diff --git a/app/models/user.rb b/app/models/user.rb index 5974e9c..60a7402 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable diff --git a/app/services/executors/base.rb b/app/services/executors/base.rb index 088d336..c069a65 100644 --- a/app/services/executors/base.rb +++ b/app/services/executors/base.rb @@ -1,26 +1,30 @@ -class Executors::Base - attr_reader :model_version +# frozen_string_literal: true - def initialize(model_version) - @model_version = model_version - end +module Executors + class Base + attr_reader :model_version + + def initialize(model_version) + @model_version = model_version + end - def call(prompt) - model = model_version.model - uri = URI.parse(model.url) - header = {'Content-Type': 'application/json'} - data = model_version.configuration.merge(prompt: "This is a conversation between User and OLMo<|endoftext|>\n\nUser:\n#{prompt}\n OLMo: ") + def call(prompt) + model = model_version.model + uri = URI.parse(model.url) + header = { 'Content-Type': 'application/json' } + data = model_version.configuration.merge(prompt: "This is a conversation between User and OLMo<|endoftext|>\n\nUser:\n#{prompt}\n OLMo: ") - http = Net::HTTP.new(uri.host, uri.port) - request = Net::HTTP::Post.new(uri.request_uri, header) - request.body = data.to_json - http.read_timeout = 2000 - response = http.request(request) + http = Net::HTTP.new(uri.host, uri.port) + request = Net::HTTP::Post.new(uri.request_uri, header) + request.body = data.to_json + http.read_timeout = 2000 + response = http.request(request) - return { status: :completed, result: response.body } if response.code.to_i == 200 + return { status: :completed, result: response.body } if response.code.to_i == 200 - { status: :failed, result: response.body } - rescue - { status: :failed } + { status: :failed, result: response.body } + rescue StandardError + { status: :failed } + end end end diff --git a/app/services/executors/openai.rb b/app/services/executors/openai.rb index d9d408e..692fbc2 100644 --- a/app/services/executors/openai.rb +++ b/app/services/executors/openai.rb @@ -1,24 +1,28 @@ -class Executors::Openai < Executors::Base - def initialize(model_version) - @client = OpenAI::Client.new(access_token: model_version.api_key, log_errors: true ) - super(model_version) - end +# frozen_string_literal: true - def call(prompt) - model = model_version.model +module Executors + class Openai < Executors::Base + def initialize(model_version) + @client = OpenAI::Client.new(access_token: model_version.api_key, log_errors: true) + super(model_version) + end - parameters = model_version.configuration.merge(messages: [{ role: "user", content: prompt }]) + def call(prompt) + model_version.model - result = client.chat(parameters: parameters) + parameters = model_version.configuration.merge(messages: [{ role: 'user', content: prompt }]) - { status: :completed, result: result.to_json.to_s } - rescue => e - return { status: :failed, result: e.response[:body].to_json.to_s } if e.respond_to?(:response) + result = client.chat(parameters:) - { status: :failed } - end + { status: :completed, result: result.to_json.to_s } + rescue StandardError => e + return { status: :failed, result: e.response[:body].to_json.to_s } if e.respond_to?(:response) - private + { status: :failed } + end - attr_reader :client + private + + attr_reader :client + end end diff --git a/app/services/model_executor.rb b/app/services/model_executor.rb index 2dfc3fa..837175e 100644 --- a/app/services/model_executor.rb +++ b/app/services/model_executor.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ModelExecutor attr_reader :executor diff --git a/app/views/chats/_chat.html.erb b/app/views/chats/_chat.html.erb deleted file mode 100644 index 2a32089..0000000 --- a/app/views/chats/_chat.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -
- Title: - <%= chat.title %> -
- -<%= notice %>
- -- <%= link_to "Show this chat", chat %> -
- <% end %> -<%= notice %>
- -<%= render @chat %> - -