From 2d2b110d51e5bdeed39c85747fd768637cf59737 Mon Sep 17 00:00:00 2001 From: CoralineAda Date: Tue, 27 Aug 2024 11:33:41 -0500 Subject: [PATCH] Finish adding comments to all methods --- app/models/codebook.rb | 5 ++--- app/models/experiences.rb | 5 ++--- app/services/derive_themes.rb | 6 +++--- app/services/export_to_graph.rb | 11 +++++++++-- app/services/import_from_csv.rb | 29 ++++++++++++++++------------- app/services/sentiment_analysis.rb | 2 +- 6 files changed, 33 insertions(+), 25 deletions(-) diff --git a/app/models/codebook.rb b/app/models/codebook.rb index 7444cd6..fee3b6c 100644 --- a/app/models/codebook.rb +++ b/app/models/codebook.rb @@ -1,12 +1,11 @@ # A Codebook is a collection of codes applied to a given context. - class Codebook - + # Used to label and display a Category query. def self.category_query(context) { explainer: "// Show me a graph of \"#{context}\"-related categories and their associated codes.", - query: "MATCH (cat:Category)-[:CATEGORIZED_AS]-(c:Code) WHERE cat.context=\"#{context}\" RETURN cat,c" + query: "MATCH (cat:Category)-[:CATEGORIZED_AS]-(c:Code) WHERE cat.context=\"#{context}\" RETURN cat,c" } end diff --git a/app/models/experiences.rb b/app/models/experiences.rb index bdd2cda..8a22dae 100644 --- a/app/models/experiences.rb +++ b/app/models/experiences.rb @@ -1,9 +1,8 @@ # Experiences defines the unique relation (edge) between a Persona and a Code. - class Experiences - + include ActiveGraph::Relationship - + from_class :Persona to_class :Code creates_unique :all diff --git a/app/services/derive_themes.rb b/app/services/derive_themes.rb index 5cf3c81..e272a40 100644 --- a/app/services/derive_themes.rb +++ b/app/services/derive_themes.rb @@ -5,7 +5,7 @@ class DeriveThemes # This is the prompt sent to the selected AI agent to provide instructions on category derivision. PROMPT = %{ You are a social researcher doing data analysis. Please generate a list of the 20 most relevant themes from the following list of codes. The themes should be all lowercase and contain no punctuation. Codes should be stripped of quotation marks. Return each code with an array of its categories in JSON format. Use this JSON as the format: - + { "themes" : [ { @@ -14,10 +14,10 @@ class DeriveThemes } ] } - + The codes are as follows: } - + def self.perform(text) new(text).perform end diff --git a/app/services/export_to_graph.rb b/app/services/export_to_graph.rb index 0aff7ce..4b5a75e 100644 --- a/app/services/export_to_graph.rb +++ b/app/services/export_to_graph.rb @@ -1,3 +1,4 @@ +# Translates data from a SurveyResponse into nodes in the graph database. class ExportToGraph attr_accessor :survey_response @@ -12,16 +13,20 @@ def initialize(survey_response_id) def perform return false unless survey_response + + # Destroy the existing persona so that neo4j will reap orphaned nodes like Codes and Identities. Persona.find_or_initialize_by(survey_response_id: survey_response.id).destroy + + # Build the codes and identities populate_experience_codes populate_id_codes + return true end private - # Hydrates the associated Persona with data from the SurveyResponse. - # Note that this operation is destructive to a Persona that already exists. + # Hydrates a new Persona with data from the SurveyResponse. def persona @persona ||= Persona.find_or_create_by( name: "Persona #{survey_response.identifier}", @@ -30,6 +35,7 @@ def persona ) end + # Creates Code nodes and connects them to the associated Persona. def populate_experience_codes contexts_and_codes = { "age" => survey_response.age_exp_codes, @@ -56,6 +62,7 @@ def populate_experience_codes end + # Creates Identity nodes and connects them to the associated Persona. def populate_id_codes contexts_and_codes = { "age" => survey_response.age_id_codes, diff --git a/app/services/import_from_csv.rb b/app/services/import_from_csv.rb index 270f999..38f1c7b 100644 --- a/app/services/import_from_csv.rb +++ b/app/services/import_from_csv.rb @@ -1,26 +1,26 @@ -# SurveyResponse objects are upserted when a survey data CSV file is imported. +# Upserts SurveyResponse objects CSV file is imported. This operation is non-destructive. class ImportFromCsv - attr_accessor :record, :survey_response + attr_accessor :record REQUIRED_FIELDS = [:age_given] - + # Given a file handle to a data file, parse the file contents as CSV and hydrate SurveyResponse records in serial. def self.perform(file_handle) CSV.read(file_handle, headers: true).each do |record| - new(record).import + new(record).perform end end - + def initialize(record) @record = record - @survey_response ||= SurveyResponse.find_or_initialize_by(response_id: record['ResponseId']) end - # Hydrates a SurveyResponse object from a record in the imported CSV data file. - def import + # Hydrates a sufficiently complete SurveyResponse object from a row in the imported CSV data file. + def perform return unless record_valid? - + survey_response = SurveyResponse.find_or_initialize_by(response_id: record['ResponseId']) + survey_response.update( age_given: record['age_given'], age_exp: record['age_exp'], @@ -47,14 +47,17 @@ def import end private - + + # Pronoun data can come from a radio button or a freeform text field. We want to distinguish between the two by + # flagging freeform answers as "self-described". def pronouns return "#{record['pronouns_given_5_TEXT']} (self-described)" if record['pronouns_given'] == "self-describe" return record['pronouns_given'] end - + + # If a SurveyResponse doesn't contain a response for the required fields, it will be considered invalid. def record_valid? REQUIRED_FIELDS.select{ |field| record[field.to_s].present? }.count == REQUIRED_FIELDS.count end - -end \ No newline at end of file + +end diff --git a/app/services/sentiment_analysis.rb b/app/services/sentiment_analysis.rb index 6233ac0..8ba23b6 100644 --- a/app/services/sentiment_analysis.rb +++ b/app/services/sentiment_analysis.rb @@ -21,7 +21,7 @@ def initialize(text) @text = text end - # Uses the OpenAI client to pass the prompt and text through the API for sentiment analysis. + # Uses the OpenAI client to pass the prompt and valid text through the API for sentiment analysis. def perform return false unless text.present?