Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ruby 3.3.6
5 changes: 4 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ gem 'addressable'
gem 'anyway_config'
gem 'aws-sdk-s3'
gem 'bourbon', '~> 4.0.2'
gem 'bcrypt', '~> 3.1.7'
gem 'clearance', '~> 2.5.0'
gem 'clearance-deprecated_password_strategies'
gem 'coffee-rails'
Expand All @@ -25,7 +26,9 @@ gem 'jbuilder'
gem 'jquery-rails', '~> 4.1.1'
gem 'jquery-ui-rails', '~> 3.0.1'
gem 'magnific-popup-rails'
gem 'nokogiri', '~> 1.18.9'
gem 'nio4r', '>= 2.7.3'
gem 'nokogiri', '~> 1.19'
gem 'ruby-openai'
gem 'pg', '~> 1.4.4'
gem 'puma'
gem 'rack-attack'
Expand Down
32 changes: 29 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ GEM
email_validator (2.2.4)
activemodel
erubi (1.13.1)
event_stream_parser (1.0.0)
execjs (2.10.0)
factory_bot (6.5.1)
activesupport (>= 6.1.0)
Expand All @@ -189,7 +190,16 @@ GEM
railties (>= 5.0.0)
faker (2.23.0)
i18n (>= 1.8.11, < 2)
ffi (1.17.1)
faraday (2.8.1)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (3.0.2)
ffi (1.17.3)
ffi (1.17.3-x86_64-darwin)
ffi (1.17.3-x86_64-linux-gnu)
ffi-compiler (1.3.2)
ffi (>= 1.15.5)
rake
Expand Down Expand Up @@ -266,6 +276,7 @@ GEM
mocha (1.2.1)
metaclass (~> 0.0.1)
msgpack (1.8.0)
multipart-post (2.4.1)
net-imap (0.5.12)
date
net-protocol
Expand All @@ -277,9 +288,13 @@ GEM
net-protocol
newrelic_rpm (9.22.0)
nio4r (2.7.5)
nokogiri (1.18.9)
nokogiri (1.19.0)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.19.0-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.19.0-x86_64-linux-gnu)
racc (~> 1.4)
pg (1.4.6)
pp (0.6.2)
prettyprint
Expand Down Expand Up @@ -391,6 +406,11 @@ GEM
rspec-support (~> 3.13)
rspec-support (3.13.2)
ruby-next-core (1.1.2)
ruby-openai (7.3.1)
event_stream_parser (>= 0.3.0, < 2.0.0)
faraday (>= 1)
faraday-multipart (>= 1)
ruby2_keywords (0.0.5)
rubyzip (2.4.1)
sass (3.7.4)
sass-listen (~> 4.0.0)
Expand Down Expand Up @@ -490,11 +510,15 @@ GEM

PLATFORMS
ruby
x86_64-darwin-20
x86_64-linux
x86_64-linux-gnu

DEPENDENCIES
addressable
anyway_config
aws-sdk-s3
bcrypt (~> 3.1.7)
bootsnap (>= 1.1.0)
bourbon (~> 4.0.2)
bourne
Expand Down Expand Up @@ -525,7 +549,8 @@ DEPENDENCIES
listen
magnific-popup-rails
newrelic_rpm
nokogiri (~> 1.18.9)
nio4r (>= 2.7.3)
nokogiri (~> 1.19)
pg (~> 1.4.4)
pry
pry-nav
Expand All @@ -541,6 +566,7 @@ DEPENDENCIES
redcarpet
rollbar
rspec-rails (~> 7.0.2)
ruby-openai
sassc-rails (~> 2.1)
selenium-webdriver
sham_rack
Expand Down
9 changes: 9 additions & 0 deletions app/assets/stylesheets/_base-variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ $button-pink: rgb(252, 103, 147);

$blue: rgb(34,122,255); //blue

$green-background: #a7f3d0;
$green-text: #065f46;

$yellow-background: #fef08a;
$yellow-text: #854d0e;

$red-background: #fecaca;
$red-text: #7f1d1d;

/***
* Responsiveness Sizes
*
Expand Down
45 changes: 45 additions & 0 deletions app/assets/stylesheets/_projects-analyses.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @import "base_variables";

body.project-analysis-show {
h1 {
font-size: 24px;
margin-bottom: 16px;
}

.scores-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;

th,
td {
padding: 8px;
border: 1px solid #ddd;
}

th {
background-color: #f0f0f0;
text-align: left;
font-weight: bold;
}

// Define classes for score rows using the color variables
tr.score-row--high {
background-color: $green-background;
color: $green-text;
font-weight: 900;
}

tr.score-row--medium {
background-color: $yellow-background;
color: $yellow-text;
}

tr.score-row--low {
background-color: $red-background;
color: $red-text;
}
}

// Additional styles can be defined here, following your SCSS strategies
}
11 changes: 11 additions & 0 deletions app/assets/stylesheets/_projects-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,17 @@ body.projects-index {
a.project-actions-toggle {
font-size: 1.1em;
}

a.auto-awesome {
@include button(rgb(240,240,240));
float: right;
margin-left: 10px;
text-decoration: none;

&.auto-awesome:hover {
@include button($pink);
}
}
}

.contact {
Expand Down
1 change: 1 addition & 0 deletions app/assets/stylesheets/_projects.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import 'projects-index';
@import 'projects-new';
@import 'projects-edit';
@import 'projects-analyses';
27 changes: 27 additions & 0 deletions app/controllers/project_analyses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class ProjectAnalysesController < ApplicationController
before_action :require_login
before_action :set_project

def show_or_create
# Delete existing analysis if force is true
if params[:force].to_s == "true" && @project.project_analysis.present?
@project.project_analysis.destroy
end

# Use cached analysis if it exists, otherwise generate a new one
@project_analysis = @project.project_analysis || ProjectAnalysisGenerator.new(@project.id).call

flash[:notice] = if @project_analysis.persisted?
I18n.t("project_analyses.flash.cache_loaded")
else
I18n.t("project_analyses.flash.generated")
end
render :show
end

private

def set_project
@project = Project.find(params[:project_id])
end
end
7 changes: 7 additions & 0 deletions app/jobs/application_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class ApplicationJob < ActiveJob::Base
# Automatically retry jobs that encountered a deadlock
# retry_on ActiveRecord::Deadlocked

# Most jobs are safe to ignore if the underlying records are no longer available
# discard_on ActiveJob::DeserializationError
end
9 changes: 9 additions & 0 deletions app/jobs/project_analysis_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class ProjectAnalysisJob < ApplicationJob
queue_as :default

def perform(project_id)
ProjectAnalysisGenerator.new(project_id).call
rescue => e
Rails.logger.error("Failed to generate project analysis for Project #{project_id}: #{e.message}")
end
end
1 change: 1 addition & 0 deletions app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Project < ApplicationRecord
has_many :real_photos, -> { merge(Photo.image_files.sorted) }, class_name: "Photo"
has_one :primary_photo, -> { merge(Photo.image_files.sorted) }, class_name: "Photo"
has_one :project_moderation, dependent: :destroy
has_one :project_analysis, dependent: :destroy

before_validation UrlNormalizer.new(:url, :rss_feed_url)

Expand Down
29 changes: 29 additions & 0 deletions app/models/project_analysis.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class ProjectAnalysis < ApplicationRecord
belongs_to :project, optional: true

validates :summary, :language_code, :applicant_role, :scores, presence: true

validate :validate_scores

# Serialize the tags array
# serialize :tags, Array

# Access scores as a nested object
def scores
@scores ||= ProjectAnalysisScores.new(self)
end

private def validate_scores
scores_class = ProjectAnalysisScores::SCORE_FIELDS
scores_class.each do |field|
score_value = send(:"#{field}_score")
reason = send(:"#{field}_score_reason")

if score_value.nil? || reason.blank?
errors.add(:base, "Both score and reason must be present for #{field}")
elsif score_value < 0 || score_value > 1
errors.add(:base, "Score for #{field} must be between 0.0 and 1.0")
end
end
end
end
9 changes: 9 additions & 0 deletions app/models/project_analysis_score.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# app/models/project_analysis_score.rb
class ProjectAnalysisScore
attr_accessor :score, :reason

def initialize(score:, reason:)
@score = score
@reason = reason
end
end
35 changes: 35 additions & 0 deletions app/models/project_analysis_scores.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class ProjectAnalysisScores
SCORE_FIELDS = %w[
self_interest
proximity
novelty
budget_clarity
whimsy
social_good
reach
feasibility
urgency
impact_of_grant
credibility
innovation
sustainability
community_involvement
cultural_relevance
scalability
alignment_with_mission
artistic_merit
]

def initialize(project_analysis)
@project_analysis = project_analysis
end

SCORE_FIELDS.each do |field|
define_method(field) do
ProjectAnalysisScore.new(
score: @project_analysis.send(:"#{field}_score"),
reason: @project_analysis.send(:"#{field}_score_reason")
)
end
end
end
Loading